mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-08 17:01:40 +00:00
Compare commits
1096 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 12e9f7b941 | |||
| 443b8c2079 | |||
| 826316cb2b | |||
| 491dc57098 | |||
| 19ed074b4a | |||
| 2cfe74ce09 | |||
| b0b844ea5a | |||
| 2d0812d46e | |||
| f5b7d0db59 | |||
| 68068cb816 | |||
| 40d2c237fc | |||
| 7e089ab8b5 | |||
| 8ee86f9968 | |||
| 2590bd01d5 | |||
| ef9b9e743f | |||
| 532f129458 | |||
| d535cf0222 | |||
| 77e02ddae4 | |||
| 98bf6c2d95 | |||
| b27482db46 | |||
| 3d2e99b5fa | |||
| 8b382df7cc | |||
| 1a57162873 | |||
| 69f25a563c | |||
| 9a85fbc225 | |||
| dd71abc672 | |||
| aa493f5987 | |||
| 784c1724d5 | |||
| 901e805d24 | |||
| 41972bba7d | |||
| 17077c74a9 | |||
| 825a493d7a | |||
| 6f5e4ec655 | |||
| de3f8cdaf4 | |||
| 241c95e6df | |||
| 8015ea217e | |||
| 285d40d586 | |||
| 80e166302a | |||
| bcf8cadc30 | |||
| 26621cbcd5 | |||
| 703c69fdde | |||
| 21981403c7 | |||
| c61bc29f06 | |||
| 90ac50f210 | |||
| 4e21298009 | |||
| a5cc0f1cef | |||
| d106f178d5 | |||
| a98ab72f67 | |||
| 62e4bf8fb3 | |||
| e532a2ead2 | |||
| fd9ba0d243 | |||
| 9a9422bea6 | |||
| f10b4bdecc | |||
| fd6de77577 | |||
| 1d5e560e66 | |||
| fa8ff0d878 | |||
| 7296bd1382 | |||
| d60b9df40c | |||
| 373934f993 | |||
| a8f6444cad | |||
| 0b2bd5d0e8 | |||
| c15120e0ae | |||
| 96cb6a73a2 | |||
| 92b7ca15cf | |||
| db65678f5e | |||
| f3a7a6594a | |||
| a786c9a9ee | |||
| ab1d34fe1d | |||
| ff542d7381 | |||
| 3023e084a6 | |||
| 0fd3c69579 | |||
| 4792fd9efe | |||
| 587edca99f | |||
| 71118fb126 | |||
| 80bdb36ccc | |||
| 013b7a763d | |||
| f0fa9ca736 | |||
| 8a197a6305 | |||
| 91d10a1465 | |||
| 1314209a89 | |||
| 45c3c27fb5 | |||
| 6e42f82e1a | |||
| 0ae1c90797 | |||
| 94bf798168 | |||
| 8c1924084a | |||
| 2bf3648966 | |||
| 5e54e84a92 | |||
| e43e02c003 | |||
| 2a026e93d5 | |||
| dafa304936 | |||
| ac4be43170 | |||
| e4fdfd2eb3 | |||
| a800a9e7c7 | |||
| 9052721a00 | |||
| 2538eeea87 | |||
| dbc3c5ebef | |||
| 45136fce6c | |||
| bf1623975c | |||
| df49f1bc1b | |||
| acde878946 | |||
| 33cbcc2510 | |||
| d583bf5284 | |||
| d12cacbd2e | |||
| 8d65086e01 | |||
| 4822b57584 | |||
| 94c3261ba8 | |||
| 5db91e52da | |||
| 68151b970a | |||
| 826752ca6c | |||
| c3adcf631a | |||
| a4c2aa8f42 | |||
| 7f9d418112 | |||
| 9b0be0fb4e | |||
| 3fdd92dc84 | |||
| 9f7a7a2c5b | |||
| 4df526f023 | |||
| 6bac067488 | |||
| 000d11daab | |||
| 3bef32bb87 | |||
| 9211f80625 | |||
| 910cdb3754 | |||
| 38f7ccdc20 | |||
| 40c2602b0e | |||
| 42e00581cd | |||
| 81f978f101 | |||
| 3e041a1fb2 | |||
| bd3118b4a3 | |||
| 4b57a7bdd6 | |||
| 6a5bfefce9 | |||
| ef7eee411b | |||
| 5ee32fb945 | |||
| 944813146e | |||
| 16cafb9f8b | |||
| b1754f7b26 | |||
| 55ac6e760d | |||
| 9d6eec0f5a | |||
| 9048ce4857 | |||
| f24944be48 | |||
| dec0c646cc | |||
| 421daa3d19 | |||
| 7bf9f637e7 | |||
| 9a2623953b | |||
| 382efc0255 | |||
| 93a80c6148 | |||
| bf50d0534b | |||
| b1ab829c14 | |||
| 7022e842bf | |||
| 65b5453ef1 | |||
| 5e32c1e55c | |||
| e6f523a2b8 | |||
| 2c8a79e186 | |||
| 13d2cf3357 | |||
| 427720f369 | |||
| d20f4a5af6 | |||
| 4936ea3ac3 | |||
| 4101407b43 | |||
| 29d3b436b4 | |||
| a2231605a5 | |||
| 4380e1d86a | |||
| 161deeb4e0 | |||
| 31eac564f6 | |||
| 99b865bbd9 | |||
| 4de617e398 | |||
| 1a1b7e93ab | |||
| f5af6ee6c0 | |||
| 94f49af00b | |||
| 39b8680f64 | |||
| 26282437cc | |||
| 6911b48a46 | |||
| acd3564429 | |||
| 20471bd33e | |||
| bb15446822 | |||
| e3b415ad54 | |||
| 27b9689e14 | |||
| 32338e2490 | |||
| e104d1aac3 | |||
| 632d36e2ba | |||
| 9a9475adcb | |||
| f307f39023 | |||
| f526277a7d | |||
| 0c8e9e7040 | |||
| a0f37cf9ea | |||
| 49c6346af7 | |||
| eb166da930 | |||
| d5216c8201 | |||
| 027226fb96 | |||
| 5dbd0249b4 | |||
| 4821226ec2 | |||
| 72c96905b9 | |||
| a8f4f0270a | |||
| 336601a7ae | |||
| d39c7bd641 | |||
| d3092090df | |||
| b88c5ee930 | |||
| 645f88a313 | |||
| a7c7a684ee | |||
| 20b3a8af3e | |||
| 0fcf1f14c8 | |||
| 327be7030f | |||
| 06589ca1c6 | |||
| 1c83b2db53 | |||
| 6f3eb84f66 | |||
| e7a8a97639 | |||
| fe1cb9e92b | |||
| f849434f24 | |||
| 8c0c216a1d | |||
| 7ed47dee67 | |||
| 4f8b430040 | |||
| b48d17c690 | |||
| 3d240deed1 | |||
| 747ddeb20c | |||
| 4afd104f3d | |||
| 4ed9166e8a | |||
| 64eb5b4d1d | |||
| 116de5daec | |||
| 0016256f57 | |||
| 0018224da7 | |||
| 334d867873 | |||
| 9caa753d27 | |||
| ba274bb164 | |||
| 50e5d5f4d5 | |||
| e7daf871b8 | |||
| f7e66d1e7f | |||
| 6cf214d2e0 | |||
| 1590ffd6ec | |||
| 752bda71af | |||
| e463dca0df | |||
| 66859c7140 | |||
| 3ff619c7ed | |||
| ad41f04f11 | |||
| e64d8750e1 | |||
| 342cce89d7 | |||
| ffa282af9d | |||
| fbc0215ef1 | |||
| 58759cf365 | |||
| 2024a24e31 | |||
| c420cc1abb | |||
| e39835d25e | |||
| 9c1660a84b | |||
| 7e9e56cd2c | |||
| a6d3619449 | |||
| dab3382b29 | |||
| 882d27fe25 | |||
| 81a9d0e747 | |||
| cb535b4ba8 | |||
| 3102a1c179 | |||
| a8effa8289 | |||
| bf3ec5e507 | |||
| 5526f421f0 | |||
| e24ddae064 | |||
| 92f4d76c81 | |||
| 59be8f742d | |||
| d2337dc692 | |||
| 2b501a93c9 | |||
| 6b8681b74a | |||
| 297812d4e2 | |||
| 7205f0165e | |||
| bf4b5928dd | |||
| 3840bd1154 | |||
| 47ec4e2240 | |||
| 622853d73d | |||
| e8b28a099f | |||
| 9a3039765f | |||
| bef9bd25f7 | |||
| 53577d9da9 | |||
| 55d07f8bba | |||
| 34b3ca307f | |||
| 028e8fb926 | |||
| 08557c2664 | |||
| a54b7863cd | |||
| 3101ccb83a | |||
| 394a7f14ad | |||
| 983745b508 | |||
| b05b62f440 | |||
| 51a9bb0ac1 | |||
| 452ab6e5bc | |||
| 0df2bfadef | |||
| 12623dd1e5 | |||
| 2eaae2bda8 | |||
| a3141b2acc | |||
| 3a4fa2e6dd | |||
| 472c3478e0 | |||
| 54d96fe167 | |||
| 229a708fc3 | |||
| 0df4edff01 | |||
| d78c9171db | |||
| 03da7bc6e4 | |||
| 34d28e8b3a | |||
| 6e8f5c84e6 | |||
| 08d003ddcd | |||
| bdf22856e4 | |||
| 4d33ed5cb8 | |||
| 4babe84941 | |||
| 4138103541 | |||
| a3894cdcda | |||
| 840f1463e5 | |||
| ad5444b974 | |||
| c0d41103fa | |||
| 3e80d3646c | |||
| c2f4c2cf74 | |||
| 45be79443f | |||
| dbc3577497 | |||
| 0a45a82109 | |||
| 07f5ac6994 | |||
| 0eb6c597f0 | |||
| b13c912c47 | |||
| 683cadeb76 | |||
| b023f6a31d | |||
| 891448e902 | |||
| 82718fad30 | |||
| 9f03a78652 | |||
| 505d234ea2 | |||
| bd5e25889a | |||
| 5609cbdde9 | |||
| caa6056f01 | |||
| 3ea3627639 | |||
| 175387bd88 | |||
| ba5049a7eb | |||
| 40b70b1815 | |||
| 54d9edfee5 | |||
| 1c2587ba19 | |||
| d09abbd260 | |||
| 5359e88f0e | |||
| 2dc01aec2d | |||
| 20b35ec4ea | |||
| 5245341cdc | |||
| 49932ba5c0 | |||
| 7a7aab01bb | |||
| d105292817 | |||
| 6fdd2049a2 | |||
| 8428b93451 | |||
| 8e2a074d70 | |||
| 1b809ed849 | |||
| 8c0bcc4ce7 | |||
| 11d0c6ef56 | |||
| 58ce86d538 | |||
| 0ba1ac7df3 | |||
| 4cfb2f1027 | |||
| 6d25047c6b | |||
| 136ec5b224 | |||
| 3ac8379187 | |||
| 6c1ad47481 | |||
| 20cd383504 | |||
| 5aebfe9f22 | |||
| fd821d08cd | |||
| 6b772d18b8 | |||
| 33635c2c40 | |||
| 7e6b758450 | |||
| 127bcaf96e | |||
| 2d59f9d53a | |||
| 1014049b05 | |||
| 37460d3df9 | |||
| 637d3e2eb6 | |||
| 2ed2e9cf86 | |||
| c1635d65eb | |||
| 495ad75b14 | |||
| 966e57e94a | |||
| ef7a1ab421 | |||
| 089bb95c9f | |||
| 7786b89269 | |||
| 589f4bda2e | |||
| 8ffc12e6cd | |||
| bd9875fae5 | |||
| 7994bcbb80 | |||
| baa0211562 | |||
| a24333486a | |||
| 452ba651d0 | |||
| 161f24d804 | |||
| 6ee283dbae | |||
| c748c8dcea | |||
| 1f68d9d5bc | |||
| 120ff2f629 | |||
| 656346741e | |||
| e21277e80a | |||
| 9f55444d2e | |||
| 05fd266a65 | |||
| 42c09deb8c | |||
| cb61873179 | |||
| dbf9f213fd | |||
| 77e0d9cca7 | |||
| 0cbe984c71 | |||
| 93cca8f7b7 | |||
| 5082fe8be4 | |||
| 834780b726 | |||
| d374fd3778 | |||
| b86b359563 | |||
| 6685ea6d7a | |||
| 0a809ba127 | |||
| 14be6b49fe | |||
| e87a1a0b32 | |||
| 768f49dcc7 | |||
| 27e335343e | |||
| 0920116178 | |||
| 1a7a4bdc3e | |||
| 5d0c04a077 | |||
| 8a316e45ed | |||
| ef97ea0593 | |||
| 19d834b19e | |||
| bc64b339a7 | |||
| af93f2a64d | |||
| a3b7a25866 | |||
| 25bae21a42 | |||
| d9679d6905 | |||
| 7a4059fbfd | |||
| 623e95cefe | |||
| 9f91109e66 | |||
| 162b665d07 | |||
| 7b728b9e6d | |||
| 6240191980 | |||
| c7329497a6 | |||
| 4bed639d9c | |||
| 5739fa7239 | |||
| e2f79ec1ba | |||
| 05e6f56911 | |||
| 19aebacbd8 | |||
| aeabe87779 | |||
| 7b3d334472 | |||
| 93c3afa1ae | |||
| 21e53d24e0 | |||
| f5d6f4f7f9 | |||
| 24b46c1f43 | |||
| ddde7bc367 | |||
| 5f6a18c212 | |||
| 5e23086947 | |||
| 472fde5599 | |||
| b3458c872f | |||
| 5bf7f53fd8 | |||
| 4d325e026e | |||
| 6622afd93a | |||
| 8b4650b169 | |||
| 6e525662c3 | |||
| d46dfb6061 | |||
| 830a03ffcd | |||
| f4463d2935 | |||
| e3a7e6137d | |||
| 01d261e168 | |||
| a792a7e2c7 | |||
| c4e56f670d | |||
| 4e28caaf8d | |||
| b7992d6a12 | |||
| efe765f71f | |||
| 5eba7af791 | |||
| 761e9d7248 | |||
| 85515e904e | |||
| 33fc2080df | |||
| 33e1fa6a14 | |||
| e7ccf7269a | |||
| 322dec6fd0 | |||
| c099234796 | |||
| 0468f12051 | |||
| 988094b796 | |||
| f36d27f7af | |||
| 3763ae18b2 | |||
| be5bd2e735 | |||
| ce782cc784 | |||
| 39b0d11746 | |||
| e06105e878 | |||
| 34e2ff31bb | |||
| c0a2e3395f | |||
| 7cd354ee7d | |||
| 95be422d4f | |||
| 111569ec1b | |||
| 9c88a35173 | |||
| 2647eacb74 | |||
| df942f6460 | |||
| 7de877823b | |||
| ea3318ae2e | |||
| fb37899b26 | |||
| 6463690a8b | |||
| 148432c011 | |||
| 478da8f658 | |||
| 9be413a308 | |||
| a9606b3044 | |||
| c419885329 | |||
| b6b41e920f | |||
| b7ce547a0c | |||
| 6cd59aa121 | |||
| 8439e5b46d | |||
| 403f64a0d0 | |||
| 6bffee83fe | |||
| f3e20ae450 | |||
| 352b14f07d | |||
| d7bcd00904 | |||
| afce8b37c4 | |||
| a2b575eec8 | |||
| eb87d50548 | |||
| f64246f7c5 | |||
| c5495d83e4 | |||
| 095801faa1 | |||
| 07954122fb | |||
| b347a488af | |||
| 0429e765b5 | |||
| 33220fa78c | |||
| effcecc75f | |||
| 85f872d3b8 | |||
| f3b3e2a441 | |||
| 25d68d320d | |||
| c38ac108cc | |||
| d14d63dd5c | |||
| 34d04c0da7 | |||
| 6c4fee1028 | |||
| ada503dbf1 | |||
| 8d0c95a939 | |||
| 7ba0b04031 | |||
| 688a652bc1 | |||
| d839238949 | |||
| f91ac2b375 | |||
| 8792a8d750 | |||
| f981c43042 | |||
| 8c26037f84 | |||
| 96ec925f31 | |||
| ee16deabe5 | |||
| 4f31b9467a | |||
| f6645b19ef | |||
| f2dbf7d063 | |||
| 49e5f2944c | |||
| fae9661efd | |||
| b90b39a894 | |||
| c7c5e692d3 | |||
| 93c2ca6267 | |||
| 430ab54602 | |||
| 08522c9fd7 | |||
| 475b8554a8 | |||
| 7bea054c1e | |||
| 490c35bf60 | |||
| b019ff6aed | |||
| 4c6ca83528 | |||
| 9ba5e8fd88 | |||
| 2e36793af2 | |||
| e3d2621ea9 | |||
| ebfe8f9c54 | |||
| 132e5d5f6e | |||
| 62794d4b07 | |||
| fd7f6e1f26 | |||
| b00acd3f67 | |||
| f12d8eeaa6 | |||
| 85524170dd | |||
| c67de4bbb3 | |||
| 36c52b3bea | |||
| ceff8a8822 | |||
| a58f23fae2 | |||
| b696df0da1 | |||
| 94224411a9 | |||
| 5c7e7cab1a | |||
| 29323e4f74 | |||
| aa0a6aa5d1 | |||
| d10efe69cd | |||
| fb1fed247e | |||
| 59d7e0cad3 | |||
| ae0afe2c0a | |||
| 3edb057178 | |||
| 04e3018f3c | |||
| f81616a6fb | |||
| f58539d6d8 | |||
| 90bdf03f54 | |||
| 6e87a21806 | |||
| d94eb9a96e | |||
| ac5800326b | |||
| 901ef57d60 | |||
| b604e5cf99 | |||
| 1e79eb535a | |||
| 6f7afd4b2a | |||
| a90936a7de | |||
| 7c1cf6ebd0 | |||
| 7eb1346407 | |||
| 771b1f3d3c | |||
| 3fb96cad0b | |||
| 23beb096a0 | |||
| 101ef69ae9 | |||
| e60202b738 | |||
| 1e8b1d9c9c | |||
| a27e516011 | |||
| 69c8b7c1c8 | |||
| c25cff6bad | |||
| 48a61219f7 | |||
| 84813084d0 | |||
| 5e0da9725a | |||
| 9a43658716 | |||
| f3f4c41f8d | |||
| 273c977f66 | |||
| 0adcb9ae20 | |||
| 1751cf1c95 | |||
| 1704862d0d | |||
| d7c275e941 | |||
| 1b9a28d799 | |||
| 68b432f6c0 | |||
| af2799acd4 | |||
| c093dc0335 | |||
| 834e05a01c | |||
| 4680298bee | |||
| be39f30029 | |||
| 3919c1f32e | |||
| e02bbefa68 | |||
| 5c497c8f6c | |||
| 942d34ee39 | |||
| 45ec08f840 | |||
| be3dbce9f4 | |||
| 20c189c321 | |||
| 97c5126a77 | |||
| ff64ce1e0e | |||
| 4f6e8a7d56 | |||
| 93ece6b3ea | |||
| ced9d8c917 | |||
| ef0e9d9eb4 | |||
| 3c2fbcc4e1 | |||
| a6ffa7fc42 | |||
| 0f825b7050 | |||
| 845dd13870 | |||
| d713b7e06a | |||
| e3e4fba63a | |||
| 78b904dfeb | |||
| 00c70fa8fb | |||
| d34c3b4b20 | |||
| 033075f809 | |||
| 1d8f6addf8 | |||
| 26a9167eea | |||
| 5fae7a5992 | |||
| 7edca081bf | |||
| 08e4d16f28 | |||
| 470e8e772e | |||
| ea609af394 | |||
| 8ac18752b2 | |||
| 95acd4c517 | |||
| 7ce795def3 | |||
| 8e4febecc0 | |||
| 195979d4f0 | |||
| ab0e47c55f | |||
| 9f362853d6 | |||
| 79e1e0ec04 | |||
| f446f25cee | |||
| a02b189f69 | |||
| 8312853b99 | |||
| be326e13ed | |||
| a2aa2bf9eb | |||
| b9e9bfeceb | |||
| dd8ee915c3 | |||
| 7fdbc9811d | |||
| 2edf867818 | |||
| e4a7d2a149 | |||
| 37f7fbecca | |||
| 0f993b32f4 | |||
| f71ee35f57 | |||
| 1856c499b7 | |||
| 06cad59fa2 | |||
| 8e69f84430 | |||
| 9e3fe84c66 | |||
| 9ad68db0dc | |||
| 40f3447ad1 | |||
| c8cc8ab1c8 | |||
| 4faa66f9b8 | |||
| 5705f24f3e | |||
| 52d035d09a | |||
| 921e343187 | |||
| 50ea73a28f | |||
| 3275119d1d | |||
| 026b4853a2 | |||
| cd132473f5 | |||
| 06c1ea9d2c | |||
| b058647d46 | |||
| 8e44290341 | |||
| 5d7b392415 | |||
| 0383221d00 | |||
| 678d422ec8 | |||
| eade74c919 | |||
| 9074f25e93 | |||
| 4b5790e83a | |||
| 470b08cd04 | |||
| d88c93a150 | |||
| 7101ac22c8 | |||
| 1b7d38a56d | |||
| de5864fc72 | |||
| 195d68cd0a | |||
| d8a11dd096 | |||
| 63b0488909 | |||
| 3abee03b9b | |||
| f1709dc71a | |||
| 6b2c8ad23e | |||
| 8ce4bbdf61 | |||
| e2cf5f4826 | |||
| 332a9a571f | |||
| ac9505506c | |||
| 257c28d450 | |||
| f95ad29c7a | |||
| 93c2f93c44 | |||
| 77d53429e3 | |||
| fa76aa9bb0 | |||
| f0e07f3447 | |||
| 80f0ff688d | |||
| 222cbe73d3 | |||
| ecff54c480 | |||
| 2d58a1bc7c | |||
| 5667f3f94a | |||
| 5d6160b47a | |||
| 37905c6725 | |||
| 99bde93af5 | |||
| e6ff78fa29 | |||
| c08aa3216d | |||
| da0b350378 | |||
| 4354361a13 | |||
| 51409aff8f | |||
| c94ed73b8d | |||
| 90e4f21f29 | |||
| 3ba2f781d8 | |||
| aec20057c7 | |||
| 5c107eb165 | |||
| 3d1ea31098 | |||
| 3d24b67146 | |||
| 18c87b515b | |||
| 11a95e7045 | |||
| 714a365942 | |||
| 739bbcc744 | |||
| 6a275d04b9 | |||
| e8ae491dc3 | |||
| 8e2f528a99 | |||
| 00215867c0 | |||
| 1e86a31b81 | |||
| f0c4ce5753 | |||
| ea514e9528 | |||
| 229b123798 | |||
| 86c9d7074b | |||
| bc000fcbab | |||
| a171b2b9b0 | |||
| 8a92e1a766 | |||
| efd6eb7f97 | |||
| 7ed98869d2 | |||
| 72d8b5377c | |||
| 8efd9757b7 | |||
| a0f5a422e2 | |||
| 8a950b1475 | |||
| d2ce8d70b1 | |||
| ac1a8f6d16 | |||
| 7883953290 | |||
| 64dc2ea95c | |||
| e064098f84 | |||
| 8dadb71648 | |||
| 9d757e1b3c | |||
| 92032b6e3b | |||
| 202b226ea0 | |||
| 1e8c7ef7f0 | |||
| 59035e7ce2 | |||
| 2c332199b1 | |||
| ecf67fe939 | |||
| f1099fc3b1 | |||
| 16e8fff9ca | |||
| 0f857283e8 | |||
| 1def5db7e4 | |||
| e9bd18fd4b | |||
| fb98275f50 | |||
| 97a62f45d0 | |||
| 4ebee68736 | |||
| a26253321f | |||
| 4b90e618b0 | |||
| 21b35767ba | |||
| e6fbfee766 | |||
| 3cba5e6e94 | |||
| 6d6e7c2982 | |||
| fd4086aa8d | |||
| cd2b0c3a05 | |||
| 42067de44c | |||
| 240133515a | |||
| b7f23ee701 | |||
| 4a85e5e7a5 | |||
| 3a507ca061 | |||
| 6bcabfd567 | |||
| 435eb7ae10 | |||
| 17e153d0c5 | |||
| aebb9e324b | |||
| 90ad3a4a93 | |||
| 478bda30bc | |||
| 69535800b5 | |||
| ee2303d965 | |||
| b792aba95f | |||
| 8f55aa732d | |||
| 2c2be389fb | |||
| 62a0f21a57 | |||
| 3c418e8e0a | |||
| ea6fbc77dd | |||
| be10bc46ca | |||
| f4fd3a5ca1 | |||
| 685717b8b8 | |||
| 8725c66306 | |||
| cbbdb61a0c | |||
| b3167cf1e6 | |||
| 44f785cce0 | |||
| 8e998ec7db | |||
| fc50e6ac23 | |||
| 815ed07192 | |||
| 009870135f | |||
| dbc59fe346 | |||
| 08aeb80f58 | |||
| 7f2729c956 | |||
| 4d6e25fb69 | |||
| 37aadcbfbf | |||
| 74a3f131be | |||
| 77b72a9dde | |||
| c644ffbe5e | |||
| aa03da20a8 | |||
| 42acc7224c | |||
| 53fadd9808 | |||
| 4afc568a41 | |||
| 906fefaf35 | |||
| 90a2c445ea | |||
| cae24a9492 | |||
| 8b3d581131 | |||
| c13eb9e131 | |||
| 3b169219af | |||
| 83243ec514 | |||
| b5c4eb3b6f | |||
| a298903fdd | |||
| ccb24948df | |||
| 5bdb4ce668 | |||
| 9909e2f7e2 | |||
| 38d1ec7a78 | |||
| 85ddae1228 | |||
| 06c3f8d6a9 | |||
| b04ca74308 | |||
| 7c0944e43b | |||
| a1c660f4ab | |||
| 2a5974fde1 | |||
| e2ffd0b6d6 | |||
| 9bff4876c5 | |||
| 42188904af | |||
| 414d7bb810 | |||
| 01269e5dd5 | |||
| 0253c1ddbe | |||
| 3f5d30f497 | |||
| 3d2ab25175 | |||
| d4dc933b99 | |||
| d54c1cdc9c | |||
| c848a7dbe0 | |||
| 60cf4ab757 | |||
| 2c3fa89dd0 | |||
| e9c7cf235b | |||
| fefa8a0563 | |||
| 04acfe1169 | |||
| 0e25787df3 | |||
| 3c3bee71d1 | |||
| 37f0e09947 | |||
| 39e26dff46 | |||
| 2f129556fd | |||
| a1d584796a | |||
| c6d5adfa42 | |||
| 1e262c8768 | |||
| d8919c50ab | |||
| 416b163050 | |||
| 1d1fb6d27a | |||
| 9fedbbff6d | |||
| 1c1097c8a4 | |||
| 884b3fe850 | |||
| 81ee60079e | |||
| 426b1279e3 | |||
| 1142db3265 | |||
| 191c029546 | |||
| 9bcfe2f50e | |||
| fa585e60ee | |||
| 0ff9de3cd9 | |||
| 63c3b54762 | |||
| d7f990d8bd | |||
| b59e8e22a7 | |||
| 25a5135e8d | |||
| 4c574df1a4 | |||
| f3d5954aee | |||
| 7d145a5f69 | |||
| 5b30dfc580 | |||
| e1bb6c95c3 | |||
| edc6f8ebd4 | |||
| ee56aad90d | |||
| 5c1ac39f19 | |||
| 0fd2f04f08 | |||
| b171bd4a14 | |||
| 54a9d72e25 | |||
| 798597d5d9 | |||
| f7453c033a | |||
| bf76bd17b2 | |||
| 59d2d227d9 | |||
| 4a3a0bff71 | |||
| 8ecc1269d7 | |||
| 614148e5e4 | |||
| 74e495cec0 | |||
| 0ceef8fe67 | |||
| 562f38756f | |||
| 76d3823bd4 | |||
| 28560d164c | |||
| 923f1212f5 | |||
| e9f551ea71 | |||
| b9c5b0e6c8 | |||
| 4953b35849 | |||
| 83e5096570 | |||
| 5008c3503d | |||
| ce38854cff | |||
| 24e2aece0b | |||
| 43f5d446ec | |||
| 50a467fda5 | |||
| 0da0e63687 | |||
| e35cefac52 | |||
| 84e7a86e77 | |||
| 82a1e33386 | |||
| 827c6fd407 | |||
| 851fadb4ec | |||
| 90f72c4b2c | |||
| 7ed219af70 | |||
| d1a1759016 | |||
| acc4af87d6 | |||
| ee75545ecd | |||
| 58b5838da9 | |||
| e171e308d0 | |||
| 645315a8f4 | |||
| 5ee9bed590 | |||
| 0f88520e75 | |||
| 481515f5ae | |||
| a33f5b6e17 | |||
| 10bec3eee0 | |||
| da0af77570 | |||
| a6094f50b9 | |||
| c3f1b41860 | |||
| 4122759f1a | |||
| a583339492 | |||
| f12e980bfe | |||
| 4979deb111 | |||
| c575352d20 | |||
| 2f8fa3282b | |||
| 993e322a8e | |||
| 61ccd8a7cf | |||
| 450baf224f | |||
| 7b2197fa37 | |||
| cde1c5f2ee | |||
| 33772a4710 | |||
| 178c34fb22 | |||
| 17ecc43f78 | |||
| 72999e04d9 | |||
| f191b1fdd2 | |||
| d095bfecde | |||
| 2e1699beea | |||
| 5c07c8dc95 | |||
| 0fa05faee8 | |||
| 21e8a1e8e6 | |||
| 2e6601b3e7 | |||
| 634932e6e7 | |||
| a041d289c6 | |||
| 01f8882311 | |||
| f2bdfbd049 | |||
| c7bf03e8f8 | |||
| 18e451b874 | |||
| f4d58b3969 | |||
| 76a3146b70 | |||
| fe70acb541 | |||
| a52901344c | |||
| d0e26f07fc | |||
| 5270710fc2 | |||
| ed8cc620ea | |||
| 9b13ed3f38 | |||
| 801c7da40f | |||
| 4be7da1a43 | |||
| a0db3a3406 | |||
| 18f8d7b3a3 | |||
| 010e05308d | |||
| 973fa9ccb5 | |||
| 0d42a293ad | |||
| a02a06a0e3 | |||
| d3438335a2 | |||
| a0bb589ed3 | |||
| 056bcd12d0 | |||
| fe699e0a81 | |||
| 4eee9a1936 | |||
| 8c1710cae1 | |||
| e2d3b3734f | |||
| b243572d23 | |||
| 3224a2cf83 | |||
| a2d91f9331 | |||
| 0301e2fb1b | |||
| 0036bd2dc2 | |||
| 0877bb0ac3 | |||
| e62ce005dc | |||
| b6e2d78bfa | |||
| bf292cccd0 | |||
| 9d730054dd | |||
| 2dc5cd44b7 | |||
| fcbe93c4c2 | |||
| 89b3b96f1e | |||
| 16a82f035f | |||
| b562508f5b | |||
| a13042f227 | |||
| 3cbb47a831 | |||
| 7d806296c1 | |||
| d6bd0c861b | |||
| 8164c90ba0 | |||
| fff6f97651 | |||
| 6a5d5dcb12 | |||
| bb3dc351b8 | |||
| 90946e0877 | |||
| 7895835ca3 | |||
| 7caa4e3e1d | |||
| d721dabf3b | |||
| 9087bc65a7 | |||
| ccf4e84e18 | |||
| 0f1db1267b | |||
| 431e993ba3 | |||
| d912e73282 | |||
| 106da12444 | |||
| 89a015724b | |||
| 8b63959509 | |||
| 0a8791e04e | |||
| 318779196b | |||
| d076fa588b | |||
| 6190771817 | |||
| 206a9cf5d0 | |||
| d4b51a82e7 | |||
| a749775045 | |||
| 26ed16ba52 | |||
| 7b4d8734ed | |||
| 455d382a9e | |||
| c9313c8e02 | |||
| b44a88d203 | |||
| 921c3eb2d3 | |||
| d5efe45b0b | |||
| b8a7b5426d | |||
| 89bea19b75 | |||
| 5c0eb05482 | |||
| c9ff455812 | |||
| fdf1b29682 | |||
| f3af39546b | |||
| 44ddc5e6dc | |||
| c9db70c7c3 | |||
| c7ddc0643e | |||
| 3a9e90f94f | |||
| db6630c1f8 | |||
| c20afd24a5 | |||
| 7b82bfb477 | |||
| 3e00139a87 | |||
| 23beb5691c | |||
| c6a265adf8 | |||
| 94d214808e | |||
| a58b2ede63 | |||
| e5c20a009d | |||
| b590747db9 | |||
| 2532ba30e4 | |||
| 9096895bdb | |||
| 82143f226e | |||
| 22a8d9a17b | |||
| 4385f3b14d | |||
| 3cba242295 | |||
| 822fa91f4d | |||
| 266d6f4c97 | |||
| 8406c5243c | |||
| 810d3eab1e | |||
| 17f6e67706 | |||
| f5c32adff1 | |||
| bb43dec90f | |||
| 0e5edbcd84 | |||
| 68fc361d96 | |||
| 06b4fcb066 | |||
| 85d5d86c84 | |||
| 78f4d7d592 | |||
| 92bc7b13cb | |||
| e518146bd6 | |||
| e9eb7db620 | |||
| 1068070037 | |||
| 3d302619c5 | |||
| 48febb7eff | |||
| feaa13a809 | |||
| 76cbb79c75 | |||
| 6aabbd4a55 | |||
| 48676a733f | |||
| f8c45b2a99 | |||
| 1ec14118fe | |||
| 381f711103 | |||
| b748c0a573 | |||
| c4e8a409de | |||
| 28863f90b9 | |||
| 4f60c7d48c | |||
| f70b37137d | |||
| 49d491704e | |||
| a3f17cd4e7 | |||
| b96cf38e17 | |||
| 5a994ebe28 | |||
| ffc008228d | |||
| 77ba3f5a80 | |||
| 04d4095ffe | |||
| 569fa49796 | |||
| 7abe2df066 | |||
| 9b64c6f4b9 | |||
| 771f78a671 | |||
| 3d6b330366 | |||
| 37d4e9bcbd | |||
| 7390faa654 | |||
| b7d4eb62d5 | |||
| 40a60386c8 | |||
| 9bf9f82b3b | |||
| b37a684eb9 | |||
| c97cf661a2 | |||
| 53f625346f | |||
| 608c7d9841 | |||
| 955190b517 | |||
| 462425f61d | |||
| 0a0f44b674 | |||
| 9f9a0ea3dc |
+14
@@ -0,0 +1,14 @@
|
||||
# Dependency and build folders created by the build scripts
|
||||
/deps*/
|
||||
/build*/
|
||||
/install*/
|
||||
/win/BuildDepsCache*.txt
|
||||
# IfcExpressParser residue
|
||||
/src/ifcexpressparser/express_parser.py
|
||||
# General Python residue
|
||||
__pycache__
|
||||
*.py.bak
|
||||
# Visual Studio Code files
|
||||
.vscode
|
||||
# PyCharm files
|
||||
.idea
|
||||
@@ -0,0 +1,7 @@
|
||||
[submodule "test/input"]
|
||||
path = test/input
|
||||
url = https://github.com/IfcOpenShell/files
|
||||
ignore = dirty
|
||||
[submodule "src/ifcopenshell-python/ifcopenshell/mvd"]
|
||||
path = src/ifcopenshell-python/ifcopenshell/mvd
|
||||
url = https://github.com/opensourceBIM/python-mvdxml/
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
os: linux
|
||||
dist: xenial
|
||||
sudo: required
|
||||
|
||||
before_install:
|
||||
- "sudo add-apt-repository -y ppa:freecad-community/ppa"
|
||||
- sudo apt-get update -qq
|
||||
|
||||
|
||||
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
|
||||
|
||||
script:
|
||||
- pwd
|
||||
- cd cmake
|
||||
- mkdir build
|
||||
- cd build
|
||||
- |
|
||||
cmake \
|
||||
-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.a;/lib/x86_64-linux-gnu/libz.so.1;/lib/x86_64-linux-gnu/liblzma.so.5;/usr/lib/x86_64-linux-gnu/libicuuc.so.55;/usr/lib/x86_64-linux-gnu/libicudata.so.55" \
|
||||
-DGLTF_SUPPORT=On \
|
||||
-DJSON_INCLUDE_DIR=/usr/include/json \
|
||||
..
|
||||
- sudo make -j2 install
|
||||
|
||||
- cd ../../test
|
||||
- /usr/bin/python2.7 tests.py
|
||||
|
||||
- cd input
|
||||
|
||||
- /usr/local/bin/IfcConvert -yv acad2010_walls.ifc acad2010_walls.glb
|
||||
- gltf_validator acad2010_walls.glb
|
||||
|
||||
- python -c "from __future__ import print_function; from io import open; import ifcopenshell; f = ifcopenshell.open('encoding.ifc'); print(f[1][0], file=open('encoding.txt', 'w', encoding='utf-8'))" && grep "'a' 1m³ ≤ 5m³ ≥ 10m³" encoding.txt
|
||||
|
||||
- |
|
||||
(for i in *.ifc; do \
|
||||
echo $i | tee -a log; \
|
||||
timeout 1m /usr/local/bin/IfcConvert -yv "$i" "$i.dae" --validate >> log 2>&1; \
|
||||
echo $i $? >> statuses; \
|
||||
done) || true
|
||||
- echo Failed
|
||||
- grep -v 0$ statuses
|
||||
- grep -v 0$ statuses | wc -l
|
||||
- echo Succeeded
|
||||
- grep 0$ statuses
|
||||
- grep 0$ statuses | wc -l
|
||||
@@ -1,65 +0,0 @@
|
||||
IfcOpenShell
|
||||
============
|
||||
open source (LGPL) software library for working with the IFC file format
|
||||
|
||||
|
||||
http://IfcOpenShell.org
|
||||
|
||||
|
||||
Compiling on Windows
|
||||
====================
|
||||
Users are advised to use the Visual Studio .sln file in the win/ folder.
|
||||
For Windows users a prebuilt Open CASCADE version is available from the
|
||||
http://opencascade.org website. Download and install this version and
|
||||
provide the paths to the Open CASCADE header and library files to MS
|
||||
Visual Studio C++.
|
||||
|
||||
For building the Autodesk 3ds Max plugin, the 3ds Max SDK needs to be
|
||||
installed as well as 3ds Max itself. Please provide the include and
|
||||
library paths to Visual Studio.
|
||||
|
||||
For building the IfcPython wrapper, SWIG needs to be installed. Please
|
||||
download the latest swigwin version from http://www.swig.org/download.html.
|
||||
After extracting the .zip file, please add the extracted folder to the PATH
|
||||
environment variable. Python needs to be installed, please provide the
|
||||
include and library paths to Visual Studio.
|
||||
|
||||
|
||||
|
||||
Compiling on *nix
|
||||
====================
|
||||
Users are advised to build IfcOpenShell using the cmake file provided in
|
||||
the cmake/ folder. There might be an Open CASCADE package in your operating
|
||||
system's software repository. If not, you will need to compile Open
|
||||
CASCADE yourself. See http://opencascade.org.
|
||||
|
||||
For building the IfcPython wrapper, SWIG and Python development are
|
||||
required.
|
||||
|
||||
To build IfcOpenShell please take the following steps:
|
||||
$ cd /path/to/IfcOpenShell/cmake
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
Optionally:
|
||||
$ OCC_INCLUDE_PATH="/path/to/OpenCASCADE/include"
|
||||
$ OCC_LIBRARY_PATH="/path/to/OpenCASCADE/lib"
|
||||
$ export OCC_INCLUDE_PATH
|
||||
$ export OCC_LIBRARY_PATH
|
||||
$ cmake ../
|
||||
$ make
|
||||
|
||||
If all worked out correctly you can now use IfcOpenShell. For example:
|
||||
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
|
||||
$ unzip Munkerud_hus6_BE.zip
|
||||
$ ./IfcObj Munkerud_hus6_BE.ifc
|
||||
$ less Munkerud_hus6_BE.obj
|
||||
Or:
|
||||
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
|
||||
$ unzip Munkerud_hus6_BE.zip
|
||||
$ python
|
||||
>>> import IfcImport
|
||||
>>> IfcImport.Init('Munkerud_hus6_BE.ifc')
|
||||
>>> geom = IfcImport.Get()
|
||||
>>> geom.name
|
||||
>>> for v in geom.mesh.verts: v
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
IfcOpenShell
|
||||
============
|
||||
IfcOpenShell is an open source ([LGPL]) software library for working with the Industry Foundation Classes ([IFC])
|
||||
file format. Currently supported IFC releases are [IFC2x3 TC1] and [IFC4 Add2 TC1].
|
||||
|
||||
For more information, see
|
||||
* [http://ifcopenshell.org](http://ifcopenshell.org)
|
||||
* [http://academy.ifcopenshell.org](http://academy.ifcopenshell.org)
|
||||
|
||||
[](https://api.travis-ci.org/IfcOpenShell/IfcOpenShell)
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
* Git
|
||||
* CMake (2.6 or newer)
|
||||
* Windows: [Visual Studio] 2008 or newer with C++ toolset (or [Visual C++ Build Tools]) or [MSYS2] + MinGW
|
||||
* *nix: GCC 4.7 or newer, or Clang (any version)
|
||||
|
||||
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")
|
||||
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
|
||||
* [SWIG](http://www.swig.org/) and [Python](https://www.python.org/) - *optional*
|
||||
For building the IfcOpenShell Python interface and the Blender add-on
|
||||
* [3ds Max SDK](http://www.autodesk.com/products/3ds-max/free-trial) - *optional*
|
||||
For building the 3ds Max plug-in.
|
||||
All recent versions of 3ds Max (2014 and newer) are 64-bit only, so a 64-bit installation is assumed.
|
||||
|
||||
Building IfcOpenShell
|
||||
---------------------
|
||||
|
||||
**Note:** The path where the source code is cloned to can contain spaces but non-ASCII characters are very likely to cause problems with the build.
|
||||
|
||||
### Compiling on Windows
|
||||
The preferred way to fetch and build this project's dependencies is to use the build scripts
|
||||
in win/ folder. **See [win/readme.md] for more information**.
|
||||
|
||||
#### Using Visual Studio
|
||||
Instructions in a nutshell (**assuming Visual Studio 2015 x64 environment variables set**):
|
||||
|
||||
> cd IfcOpenShell\win
|
||||
> build-deps.cmd
|
||||
> run-cmake.bat
|
||||
|
||||
You can now open and build the solution file in Visual Studio:
|
||||
|
||||
> ..\build-vs2015-x64\IfcOpenShell.sln
|
||||
|
||||
As the scripts default to using the `RelWithDebInfo` configuration, and a freshly created solution by CMake defaults
|
||||
to `Debug`, make sure to switch the used build configuration. Build the `INSTALL` project (right-click -> Project
|
||||
Only) to deploy the headers and binaries into a single location if wanted/needed.
|
||||
|
||||
Alternatively, one can use the utility batch file(s) to build and install the project easily from the command-line
|
||||
(installing a project will build it also, if required):
|
||||
|
||||
> install-ifcopenshell.bat
|
||||
|
||||
#### Using MSYS2 + MinGW
|
||||
|
||||
Start the MSYS2 Shell and then:
|
||||
|
||||
$ cd IfcOpenShell/win
|
||||
$ ./build-deps.sh
|
||||
$ ./run-cmake.sh
|
||||
$ ./install-ifcopenshell.sh
|
||||
|
||||
#### Using Bash on Ubuntu on Windows
|
||||
|
||||
Start Bash on Ubuntu on Windows and follow the instructions below. Compiling on Ubuntu 14.04.4 LTS using GCC 4.8.4
|
||||
or Clang 3.5 has been confirmed to work.
|
||||
|
||||
### Compiling on *nix
|
||||
|
||||
The following instructions are for Ubuntu, modify as required for other operating systems. [nix/build-all.py] script
|
||||
can be experimented with and studied for pointers for other operating systems, but note that this script is not currently
|
||||
meant to be used for a typical IfcOpenShell workspace setup.
|
||||
|
||||
Note: where `make -j` is written, add a number roughly equal to the amount of CPU cores + 1.
|
||||
|
||||
**1)** Install most of the prerequisites and dependencies:
|
||||
|
||||
$ sudo apt-get install git cmake gcc g++ libboost-all-dev
|
||||
|
||||
**2a)** Either use an OCE package from your operating system's software repository
|
||||
|
||||
$ sudo apt-get install liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
|
||||
|
||||
**2b)** or (if not available, or the latest code is wanted) compile OCE yourself (note that the build takes a long time):
|
||||
|
||||
$ sudo apt-get install libftgl-dev libtbb2 libtbb-dev libgl1-mesa-dev libfreetype6-dev
|
||||
$ git clone https://github.com/tpaviot/oce.git
|
||||
$ cd oce
|
||||
$ mkdir build && cd build
|
||||
$ cmake ..
|
||||
$ make -j
|
||||
$ sudo make install
|
||||
|
||||
**2c)** or obtain and compile OCCT from http://www.opencascade.org/getocc/download/loadocc/
|
||||
|
||||
**3)** For building IfcConvert with COLLADA (.dae) support (on by default), OpenCOLLADA is needed:
|
||||
|
||||
$ sudo apt-get install libpcre3-dev libxml2-dev
|
||||
$ git clone https://github.com/KhronosGroup/OpenCOLLADA.git
|
||||
$ cd OpenCOLLADA
|
||||
Using a known good revision, but HEAD should work too:
|
||||
$ git checkout 064a60b65c2c31b94f013820856bc84fb1937cc6
|
||||
$ mkdir build && cd build
|
||||
$ cmake ..
|
||||
$ make -j
|
||||
$ sudo make install
|
||||
|
||||
**4)** For building the IfcPython wrapper (on by default), SWIG and Python development are needed, if not already available:
|
||||
|
||||
$ sudo apt-get install python-all-dev swig
|
||||
|
||||
**5)** To build IfcOpenShell please take the following steps. Alternatively use environment variables for setting the
|
||||
dependencies' paths. `OCC_INCLUDE_DIR` might be needed to set also. `OPENCOLLADA_INCLUDE_DIR` and `OPENCOLLADA_LIBRARY_DIR`
|
||||
(and potentially `PCRE_LIBRARY_DIR`) are needed if building with COLLADA support. (`-DCOLLADA_SUPPORT=0` disables it).
|
||||
|
||||
$ cd /path/to/IfcOpenShell
|
||||
$ mkdir build && cd build
|
||||
$ cmake ../cmake -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/ \
|
||||
-DOPENCOLLADA_INCLUDE_DIR="/usr/local/include/opencollada" \
|
||||
-DOPENCOLLADA_LIBRARY_DIR="/usr/local/lib/opencollada" \
|
||||
-DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/
|
||||
$ make -j
|
||||
|
||||
If all worked out correctly you can now use IfcOpenShell. See the examples below.
|
||||
|
||||
**6)** Install the project if wanted:
|
||||
|
||||
$ sudo make install
|
||||
|
||||
Installing IfcOpenShell with Conda
|
||||
----------------------------------
|
||||
Another option for building and installing IfcOpenShell is to use the popular
|
||||
[Anaconda Python Distribution](https://www.anaconda.com/download).
|
||||
The requirements are spread across a number of channels.
|
||||
You can add these channels to your configuration, or specify them all on the command line:
|
||||
|
||||
$ conda install -c conda-forge -c oce -c dlr-sc -c ifcopenshell ifcopenshell
|
||||
|
||||
Usage examples
|
||||
--------------
|
||||
|
||||
**Invoking IfcConvert from the command line**
|
||||
|
||||
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
|
||||
$ unzip Munkerud_hus6_BE.zip
|
||||
$ ./IfcConvert Munkerud_hus6_BE.ifc
|
||||
$ less Munkerud_hus6_BE.obj
|
||||
|
||||
**Using the IfcOpenShell Python interface**
|
||||
|
||||
$ wget -O duplex.zip http://projects.buildingsmartalliance.org/files/?artifact_id=4278
|
||||
$ unzip duplex.zip
|
||||
$ python
|
||||
>>> import ifcopenshell
|
||||
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
|
||||
>>>
|
||||
>>> # Accessing entity instances by type:
|
||||
>>> f.by_type("ifcwall")[:2]
|
||||
[#91=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FL9r',#1,'Basic Wall:Interior - Partition (92mm Stud):144586',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5198,#18806,'144586'), #92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')]
|
||||
>>> wall = _[0]
|
||||
>>> len(wall) # number of EXPRESS attributes
|
||||
8
|
||||
>>>
|
||||
>>> # Accessing EXPRESS attributes by name:
|
||||
>>> wall.GlobalId
|
||||
'2O2Fr$t4X7Zf8NOew3FL9r'
|
||||
>>> wall.Name = "My wall"
|
||||
>>> wall.NonExistingAttr
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File ".\ifcopenshell.py", line 14, in __getattr__
|
||||
except: raise AttributeError("entity instance of type '%s' has no attribute'%s'"%(self.wrapped_data.is_a(), name)) from None
|
||||
AttributeError: entity instance of type 'IfcWallStandardCase' has no attribute 'NonExistingAttr'
|
||||
>>> wall.GlobalId = 3
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File ".\ifcopenshell.py", line 26, in __setattr__
|
||||
self[self.wrapped_data.get_argument_index(key)] = value
|
||||
File ".\ifcopenshell.py", line 30, in __setitem__
|
||||
self.wrapped_data.set_argument(idx, entity_instance.map_value(value))
|
||||
File ".\ifc_wrapper.py", line 118, in <lambda>
|
||||
set_argument = lambda self,x,y: self._set_argument(x) if y is None else self
|
||||
._set_argument(x,y)
|
||||
File ".\ifc_wrapper.py", line 114, in _set_argument
|
||||
def _set_argument(self, *args): return _ifc_wrapper.entity_instance__set_argument(self, *args)
|
||||
RuntimeError: INT is not a valid type for 'GlobalId'
|
||||
>>> # Creating new entity instances
|
||||
>>> f.createIfcCartesianPoint(Coordinates=(1.0,1.5,2.0))
|
||||
#27530=IfcCartesianPoint((1.,1.5,2.))
|
||||
>>>
|
||||
>>> # Working with GlobalId attributes:
|
||||
>>> import uuid
|
||||
>>> ifcopenshell.guid.compress(uuid.uuid1().hex)
|
||||
'3x4C8Q_6qHuv$P$FYkANRX'
|
||||
>>> new_guid = _
|
||||
>>> owner_hist = f.by_type("IfcOwnerHistory")[0]
|
||||
>>> new_wall = f.createIfcWallStandardCase(new_guid, owner_hist, None, None, Tag='my_tag')
|
||||
>>> new_wall.ObjectType = ''
|
||||
>>> new_wall.ObjectPlacement = new_wall.Representation = None
|
||||
>>>
|
||||
>>> # Accessing entity instances by instance id or GlobalId:
|
||||
>>> f[92]
|
||||
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
|
||||
>>> f['2O2Fr$t4X7Zf8NOew3FLIE']
|
||||
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
|
||||
>>>
|
||||
>>> # Writing IFC-SPF files to disk:
|
||||
>>> f.write("out.ifc")
|
||||
|
||||
[LGPL]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/COPYING "LGPL"
|
||||
[IFC]: http://www.buildingsmart-tech.org/specifications/ifc-overview "IFC"
|
||||
[IFC2x3 TC1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc2x3-tc1-release "IFC2x3 TC1"
|
||||
[IFC4 Add1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-add1-release "IFC4 Add1"
|
||||
[Visual Studio]: https://www.visualstudio.com/ "Visual Studio"
|
||||
[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools "Visual C++ Build Tools"
|
||||
[MSYS2]: https://msys2.github.io/ "MSYS2"
|
||||
[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md"
|
||||
[nix/build-all.py]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/nix/build-all.py "nix/build-all.py"
|
||||
+642
-190
@@ -1,235 +1,687 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.1.3)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
|
||||
|
||||
project (IfcOpenShell)
|
||||
|
||||
FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
|
||||
foreach(max_year RANGE 2014 2030)
|
||||
set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}")
|
||||
if (NOT "${max_sdk}" STREQUAL "")
|
||||
MESSAGE(STATUS "Autodesk 3ds Max SDK found at ${max_sdk}")
|
||||
set(HAS_MAX TRUE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
|
||||
OPTION(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
|
||||
OPTION(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF)
|
||||
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_IFCGEOM "Build IfcGeom." ON)
|
||||
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
|
||||
OPTION(BUILD_EXAMPLES "Build example applications." ON)
|
||||
OPTION(BUILD_GEOMSERVER "Build IfcGeomServer executable." ON)
|
||||
OPTION(BUILD_CONVERT "Build IfcConvert executable." ON)
|
||||
OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
|
||||
OPTION(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF)
|
||||
if (${HAS_MAX})
|
||||
OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." ON)
|
||||
endif()
|
||||
OPTION(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF)
|
||||
|
||||
# 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)
|
||||
|
||||
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)
|
||||
endif()
|
||||
|
||||
# Specify where to install files
|
||||
IF(NOT BINDIR)
|
||||
set(BINDIR bin)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${BINDIR})
|
||||
set(BINDIR ${CMAKE_INSTALL_PREFIX}/${BINDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "BINDIR: ${BINDIR}")
|
||||
|
||||
IF(NOT INCLUDEDIR)
|
||||
set(INCLUDEDIR include)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${INCLUDEDIR})
|
||||
set(INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${INCLUDEDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
|
||||
|
||||
IF(NOT LIBDIR)
|
||||
set(LIBDIR lib)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${LIBDIR})
|
||||
set(LIBDIR ${CMAKE_INSTALL_PREFIX}/${LIBDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "LIBDIR: ${LIBDIR}")
|
||||
|
||||
set(IFCOPENSHELL_LIBARY_DIR "") # for *nix rpaths
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_definitions(-DIFC_SHARED_BUILD)
|
||||
if (MSVC)
|
||||
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
|
||||
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
|
||||
# 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}")
|
||||
endif()
|
||||
|
||||
# Create cache entries if absent for environment variables
|
||||
MACRO(UNIFY_ENVVARS_AND_CACHE VAR)
|
||||
IF ((NOT DEFINED ${VAR}) AND (NOT "$ENV{${VAR}}" STREQUAL ""))
|
||||
SET(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE)
|
||||
ENDIF()
|
||||
ENDMACRO()
|
||||
|
||||
UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(LIBXML2_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(LIBXML2_LIBRARIES)
|
||||
UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
|
||||
|
||||
if (GLTF_SUPPORT)
|
||||
UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR)
|
||||
FIND_FILE(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann)
|
||||
IF(json_hpp)
|
||||
MESSAGE(STATUS "JSON for Modern C++ header file found")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find JSON for Modern C++ header file, aborting")
|
||||
ENDIF()
|
||||
add_definitions(-DWITH_GLTF)
|
||||
endif()
|
||||
|
||||
# Set INSTALL_RPATH for target
|
||||
MACRO(SET_INSTALL_RPATHS _target _paths)
|
||||
SET(${_target}_rpaths "")
|
||||
FOREACH(_path ${_paths})
|
||||
LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_path}" isSystemDir)
|
||||
IF("${isSystemDir}" STREQUAL "-1")
|
||||
LIST(APPEND ${_target}_rpaths ${_path})
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
MESSAGE(STATUS "Set INSTALL_RPATH for ${_target}: ${${_target}_rpaths}")
|
||||
SET_TARGET_PROPERTIES(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}")
|
||||
ENDMACRO()
|
||||
|
||||
# Find Boost: On win32 the (hardcoded) default is to use static libraries and
|
||||
# runtime, when doing running conda-build we pick what conda prepared for us.
|
||||
IF(WIN32 AND ("$ENV{CONDA_BUILD}" STREQUAL ""))
|
||||
SET(Boost_USE_STATIC_LIBS ON)
|
||||
SET(Boost_USE_STATIC_RUNTIME ON)
|
||||
SET(Boost_USE_MULTITHREADED ON)
|
||||
ELSE()
|
||||
# Disable Boost's autolinking as the libraries to be linked to are supplied
|
||||
# already by CMake, and it's going to conflict if there are multiple, as is
|
||||
# the case in conda-forge's libboost feedstock.
|
||||
ADD_DEFINITIONS(-DBOOST_ALL_NO_LIB)
|
||||
IF(WIN32)
|
||||
# Necessary for boost version >= 1.67
|
||||
SET(BCRYPT_LIBRARIES "bcrypt.lib")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
set(BOOST_COMPONENTS system program_options regex thread date_time)
|
||||
if(USE_MMAP)
|
||||
if(MSVC)
|
||||
# filesystem is necessary for the utf-16 wpath
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams filesystem)
|
||||
else()
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams)
|
||||
endif()
|
||||
add_definitions(-DUSE_MMAP)
|
||||
endif()
|
||||
|
||||
if (IFCXML_SUPPORT)
|
||||
add_definitions(-DWITH_IFCXML)
|
||||
endif()
|
||||
|
||||
FIND_PACKAGE(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
|
||||
MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
|
||||
|
||||
# Find Open CASCADE header files
|
||||
IF("$ENV{OCC_INCLUDE_DIR}" STREQUAL "")
|
||||
SET(OCC_INCLUDE_DIR "/usr/include/opencascade/" CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
|
||||
# Usage:
|
||||
# set(SOME_LIRARIES foo bar)
|
||||
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" d)
|
||||
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
|
||||
# or
|
||||
# set(SOME_LIRARIES path/foo.lib)
|
||||
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" "d")
|
||||
# "path/foo.lib" -> "optimized path/foo.lib debug path/food.lib"
|
||||
# TODO Could be refined: take the library file extension as a parameter and
|
||||
# make sure the lib variable ends with not just contains it.
|
||||
function(add_debug_variants NAME LIBRARIES POSTFIX)
|
||||
set(LIBRARIES_STR "${LIBRARIES}")
|
||||
set(LIBRARIES "")
|
||||
# the result, "optimized <lib> debug <lib>", needs to be a list instead of a string
|
||||
foreach(lib ${LIBRARIES_STR})
|
||||
list(APPEND LIBRARIES optimized)
|
||||
if ("${lib}" MATCHES ".lib")
|
||||
string(REPLACE ".lib" "" lib ${lib})
|
||||
list(APPEND LIBRARIES ${lib}.lib)
|
||||
else()
|
||||
list(APPEND LIBRARIES ${lib})
|
||||
endif()
|
||||
|
||||
list(APPEND LIBRARIES debug)
|
||||
if ("${lib}" MATCHES ".lib")
|
||||
string(REPLACE ".lib" "" lib ${lib})
|
||||
list(APPEND LIBRARIES ${lib}${POSTFIX}.lib)
|
||||
else()
|
||||
list(APPEND LIBRARIES ${lib}${POSTFIX})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${NAME} ${LIBRARIES} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
if(BUILD_IFCGEOM)
|
||||
|
||||
# Find 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")
|
||||
ELSE()
|
||||
SET(OCC_INCLUDE_DIR $ENV{OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
|
||||
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} /usr/inc /usr/local/inc /usr/local/include/oce)
|
||||
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")
|
||||
ENDIF()
|
||||
|
||||
# Find Open CASCADE library files
|
||||
IF("$ENV{OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
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
|
||||
)
|
||||
|
||||
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
MESSAGE(STATUS "Use OCC_LIBRARY_DIR to specify another directory")
|
||||
ELSE()
|
||||
SET(OCC_LIBRARY_DIR $ENV{OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for opencascade 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 "TKernel" ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
|
||||
FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
IF(libTKernel)
|
||||
MESSAGE(STATUS "Library files found")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find library files, aborting")
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{ICU_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU include directory specified")
|
||||
ElSE()
|
||||
SET(ICU_INCLUDE_DIR CACHE FILEPATH "ICU header files")
|
||||
# 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.
|
||||
string(REPLACE TKerneld "${lib}" lib_path "${libTKernel}")
|
||||
string(REPLACE TKernel "${lib}" lib_path "${lib_path}")
|
||||
list(APPEND OPENCASCADE_LIBRARIES "${lib_path}")
|
||||
endforeach()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-DHAVE_NO_DLL)
|
||||
add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d)
|
||||
endif()
|
||||
if (WIN32)
|
||||
# OCC might require linking to Winsock depending on the version and build configuration
|
||||
list(APPEND OPENCASCADE_LIBRARIES ws2_32.lib)
|
||||
endif()
|
||||
|
||||
# Make sure cross-referenced symbols between static OCC libraries get
|
||||
# resolved. Also add thread and rt libraries.
|
||||
get_filename_component(libTKernelExt ${libTKernel} EXT)
|
||||
if("${libTKernelExt}" STREQUAL ".a")
|
||||
find_package(Threads)
|
||||
# OPENCASCADE_LIBRARIES repeated three times below in order to fix cyclic dependencies - use --start-group ... --end-group instead?
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
if (NOT APPLE AND NOT WIN32)
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt")
|
||||
endif()
|
||||
if (NOT WIN32)
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "dl")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif(BUILD_IFCGEOM)
|
||||
|
||||
IF(COLLADA_SUPPORT AND BUILD_CONVERT)
|
||||
# Find OpenCOLLADA
|
||||
IF("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "/usr/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ELSE()
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ENDIF()
|
||||
|
||||
IF("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
|
||||
FIND_LIBRARY(OPENCOLLADA_FRAMEWORK_LIB NAMES OpenCOLLADAFramework
|
||||
PATHS /usr/lib64/opencollada /usr/lib/opencollada /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib)
|
||||
GET_FILENAME_COMPONENT(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_FRAMEWORK_LIB} PATH)
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(OpenCOLLADAFramework NAMES OpenCOLLADAFramework OpenCOLLADAFrameworkd PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
if (OpenCOLLADAFramework)
|
||||
message(STATUS "OpenCOLLADA library files found")
|
||||
else()
|
||||
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA libraries. "
|
||||
"Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
|
||||
endif()
|
||||
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
|
||||
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
|
||||
|
||||
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
|
||||
IF(COLLADASWStreamWriter_h)
|
||||
MESSAGE(STATUS "OpenCOLLADA header files found")
|
||||
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
|
||||
SET(OPENCOLLADA_LIBRARY_NAMES
|
||||
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
|
||||
OpenCOLLADAStreamWriter UTF buffer ftoa
|
||||
)
|
||||
|
||||
# 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.
|
||||
string(REPLACE OpenCOLLADAFrameworkd "${lib}" lib_path "${OpenCOLLADAFramework}")
|
||||
string(REPLACE OpenCOLLADAFramework "${lib}" lib_path "${lib_path}")
|
||||
list(APPEND OPENCOLLADA_LIBRARIES "${lib_path}")
|
||||
endforeach()
|
||||
|
||||
if("${PCRE_LIBRARY_DIR}" STREQUAL "")
|
||||
if(WIN32)
|
||||
find_library(pcre_library NAMES pcre pcred PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
else()
|
||||
find_library(pcre_library NAMES pcre PATHS ${OPENCOLLADA_LIBRARY_DIR})
|
||||
endif()
|
||||
GET_FILENAME_COMPONENT(PCRE_LIBRARY_DIR ${pcre_library} PATH)
|
||||
else()
|
||||
find_library(pcre_library NAMES pcre pcred PATHS ${PCRE_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
if (pcre_library)
|
||||
SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR})
|
||||
if (MSVC)
|
||||
# Add release lib regardless whether release or debug found. Debug version will be appended below.
|
||||
list(APPEND OPENCOLLADA_LIBRARIES "${PCRE_LIBRARY_DIR}/pcre.lib")
|
||||
else()
|
||||
list(APPEND OPENCOLLADA_LIBRARIES "${pcre_library}")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find PCRE. "
|
||||
"Disable COLLADA_SUPPORT or fix PCRE_LIBRARY_DIR path to proceed.")
|
||||
endif()
|
||||
|
||||
IF(MSVC)
|
||||
add_debug_variants(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" d)
|
||||
ENDIF()
|
||||
ELSE()
|
||||
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA headers. "
|
||||
"Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU library directory specified")
|
||||
ElSE()
|
||||
SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files")
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
|
||||
|
||||
IF(icu)
|
||||
MESSAGE(STATUS "ICU libraries found")
|
||||
ADD_DEFINITIONS(-DHAVE_ICU)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "Unable to find ICU library files, continuing")
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "$ENV{OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "$ENV{OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ENDIF()
|
||||
|
||||
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
|
||||
|
||||
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
|
||||
IF(COLLADASWStreamWriter_h)
|
||||
MESSAGE(STATUS "OpenCOLLADA header files found")
|
||||
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
|
||||
SET(OPENCOLLADA_LIBRARIES
|
||||
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils
|
||||
OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
|
||||
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
|
||||
)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "OpenCOLLADA header files not found, continuing without COLLADA support")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(CheckIncludeFileCXX)
|
||||
|
||||
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
|
||||
STRING(REPLACE . _ STR ${INCLUDE})
|
||||
STRING(TOUPPER ${STR} STR)
|
||||
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
|
||||
IF(FOUND_${STR})
|
||||
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
|
||||
ADD_DEFINITIONS(-DHAVE_${STR})
|
||||
ENDIF(FOUND_${STR})
|
||||
ENDMACRO(CHECK_ADD_OCE_OCC_DEF)
|
||||
|
||||
CHECK_ADD_OCE_OCC_DEF(limits)
|
||||
CHECK_ADD_OCE_OCC_DEF(climits)
|
||||
CHECK_ADD_OCE_OCC_DEF(limits.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream.h)
|
||||
|
||||
IF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
IF(MSVC)
|
||||
ADD_DEFINITIONS(-D_UNICODE)
|
||||
ElSE(MSVC)
|
||||
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
|
||||
ENDIF(MSVC)
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} /usr/inc /usr/local/inc /usr/local/include/oce ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
|
||||
|
||||
ADD_LIBRARY(IfcParse STATIC
|
||||
../src/ifcparse/Ifc2x3-latebound.cpp
|
||||
../src/ifcparse/Ifc2x3.cpp
|
||||
../src/ifcparse/Ifc4-latebound.cpp
|
||||
../src/ifcparse/Ifc4.cpp
|
||||
../src/ifcparse/IfcCharacterDecoder.cpp
|
||||
../src/ifcparse/IfcGuidHelper.cpp
|
||||
../src/ifcparse/IfcHierarchyHelper.cpp
|
||||
../src/ifcparse/IfcLateBoundEntity.cpp
|
||||
../src/ifcparse/IfcParse.cpp
|
||||
../src/ifcparse/IfcSIPrefix.cpp
|
||||
../src/ifcparse/IfcSpfHeader.cpp
|
||||
../src/ifcparse/IfcUtil.cpp
|
||||
../src/ifcparse/IfcWrite.cpp
|
||||
)
|
||||
|
||||
ADD_LIBRARY(IfcGeom STATIC
|
||||
../src/ifcgeom/IfcGeomCurves.cpp
|
||||
../src/ifcgeom/IfcGeomFaces.cpp
|
||||
../src/ifcgeom/IfcGeomFunctions.cpp
|
||||
../src/ifcgeom/IfcGeomHelpers.cpp
|
||||
../src/ifcgeom/IfcGeomMaterial.cpp
|
||||
../src/ifcgeom/IfcGeomRenderStyles.cpp
|
||||
../src/ifcgeom/IfcGeomRepresentation.cpp
|
||||
../src/ifcgeom/IfcGeomShapes.cpp
|
||||
../src/ifcgeom/IfcGeomWires.cpp
|
||||
../src/ifcgeom/IfcRegister.cpp
|
||||
)
|
||||
|
||||
IF(icu)
|
||||
TARGET_LINK_LIBRARIES(IfcParse icuuc)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ENDIF()
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
|
||||
if(ENABLE_BUILD_OPTIMIZATIONS)
|
||||
if(MSVC)
|
||||
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
|
||||
# with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance
|
||||
# of IfcConvert significantly.
|
||||
# TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse)
|
||||
# C++
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
|
||||
# Linker
|
||||
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
else()
|
||||
# GCC-like: Release should use O3 but RelWithDebInfo 02 so enforce 03. Anything other useful that could be added here?
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS})
|
||||
IF(MSVC)
|
||||
# Enable solution folders (free VS versions prior to 2012 don't support solution folders)
|
||||
if (MSVC_VERSION GREATER 1600)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
endif()
|
||||
|
||||
ADD_EXECUTABLE(IfcConvert
|
||||
../src/ifcconvert/ColladaSerializer.cpp
|
||||
../src/ifcconvert/IfcConvert.cpp
|
||||
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
|
||||
../src/ifcconvert/WavefrontObjSerializer.cpp
|
||||
../src/ifcconvert/XmlSerializer.cpp
|
||||
IF(USE_VLD)
|
||||
ADD_DEFINITIONS(-DUSE_VLD)
|
||||
ENDIF()
|
||||
# Enforce Unicode for CRT and Win32 API calls
|
||||
ADD_DEFINITIONS(-D_UNICODE -DUNICODE)
|
||||
# Disable warnings about unsafe C functions; we could use the safe C99 & C11 versions if we have no need for supporting old compilers.
|
||||
ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
|
||||
ADD_DEFINITIONS(-bigobj) # required for building the big ifcXXX.objs, https://msdn.microsoft.com/en-us/library/ms173499.aspx
|
||||
# Bump up the warning level from the default 3 to 4.
|
||||
ADD_DEFINITIONS(-W4)
|
||||
IF(MSVC_VERSION GREATER 1800) # > 2013
|
||||
# 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
|
||||
if (MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
|
||||
add_definitions(-permissive-)
|
||||
endif()
|
||||
# Link against the static VC runtime
|
||||
# TODO Make this configurable
|
||||
IF("$ENV{CONDA_BUILD}" STREQUAL "")
|
||||
FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
IF(${flag} MATCHES "/MD")
|
||||
STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
IF(${flag} MATCHES "/MDd")
|
||||
STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
ENDIF()
|
||||
ElSE()
|
||||
add_definitions(-Wall -Wextra)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_definitions(-Wno-tautological-constant-out-of-range-compare)
|
||||
else()
|
||||
add_definitions(-Wno-maybe-uninitialized)
|
||||
endif()
|
||||
# -fPIC is not relevant on Windows and creates pointless warnings
|
||||
if (UNIX)
|
||||
add_definitions(-fPIC)
|
||||
endif()
|
||||
ENDIF()
|
||||
|
||||
if (IFCCONVERT_DOUBLE_PRECISION)
|
||||
SET(CONVERT_PRECISION "-DIFCCONVERT_DOUBLE_PRECISION")
|
||||
endif()
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} ${JSON_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
|
||||
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
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
ADD_EXECUTABLE(IfcGeomServer
|
||||
../src/ifcgeomserver/IfcGeomServer.cpp
|
||||
if(COMPILE_SCHEMA)
|
||||
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 "2x3" "4")
|
||||
|
||||
# Install pyparsing if necessary
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
|
||||
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
|
||||
execute_process(COMMAND pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
|
||||
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
|
||||
message(WARNING "Failed to find pip. Pip is required to automatically install pyparsing")
|
||||
endif()
|
||||
endif()
|
||||
string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND)
|
||||
if ("${PYPARSING_FOUND}" STREQUAL "-1")
|
||||
message(STATUS "Installing pyparsing")
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
if (NOT "${SUCCESS}" STREQUAL "0")
|
||||
execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
if (NOT "${SUCCESS}" STREQUAL "0")
|
||||
message(WARNING "Failed to automatically install pyparsing. Please install manually")
|
||||
endif()
|
||||
endif()
|
||||
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
|
||||
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
|
||||
if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3")
|
||||
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3")
|
||||
add_definitions(-DUSE_IFC2x3)
|
||||
elseif("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC4")
|
||||
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4")
|
||||
add_definitions(-DUSE_IFC4)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Boost >= 1.58 requires BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE to build on some Linux distros.
|
||||
if(NOT Boost_VERSION LESS 105800)
|
||||
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
|
||||
endif()
|
||||
|
||||
set(IFCOPENSHELL_LIBRARIES IfcParse)
|
||||
if (BUILD_IFCGEOM)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom_ifc2x3 IfcGeom_ifc4 IfcGeom IfcGeom_ifc2x3 IfcGeom_ifc4 IfcGeom)
|
||||
endif()
|
||||
if (BUILD_CONVERT)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} Serializers_ifc2x3 Serializers_ifc4 Serializers Serializers_ifc2x3 Serializers_ifc4 Serializers)
|
||||
endif()
|
||||
|
||||
# IfcParse
|
||||
file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h)
|
||||
file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp)
|
||||
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
|
||||
|
||||
add_library(IfcParse ${IFCPARSE_FILES})
|
||||
set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS)
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES})
|
||||
|
||||
if (BUILD_IFCGEOM)
|
||||
|
||||
# IfcGeom
|
||||
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h)
|
||||
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
|
||||
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
|
||||
|
||||
add_library(IfcGeom_ifc2x3 STATIC ${IFCGEOM_FILES})
|
||||
add_library(IfcGeom_ifc4 STATIC ${IFCGEOM_FILES})
|
||||
|
||||
set_target_properties(IfcGeom_ifc2x3 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc2x3")
|
||||
# TODO: Detect based on IfcSchema
|
||||
set_target_properties(IfcGeom_ifc4 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc4 -DUSE_IFC4")
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcGeom_ifc2x3 IfcParse ${OPENCASCADE_LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(IfcGeom_ifc4 IfcParse ${OPENCASCADE_LIBRARIES})
|
||||
|
||||
# IfcGeom (schema agnostic)
|
||||
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic/*.h)
|
||||
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic/*.cpp)
|
||||
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
|
||||
|
||||
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
|
||||
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS)
|
||||
TARGET_LINK_LIBRARIES(IfcGeom IfcGeom_ifc2x3 IfcGeom_ifc4)
|
||||
|
||||
endif(BUILD_IFCGEOM)
|
||||
|
||||
if (BUILD_CONVERT)
|
||||
|
||||
# Serializers
|
||||
file(GLOB SERIALIZERS_H_FILES ../src/serializers/*.h)
|
||||
file(GLOB SERIALIZERS_CPP_FILES ../src/serializers/*.cpp)
|
||||
set(SERIALIZERS_FILES ${SERIALIZERS_H_FILES} ${SERIALIZERS_CPP_FILES})
|
||||
file(GLOB SERIALIZERS_S_H_FILES ../src/serializers/schema_dependent/*.h)
|
||||
file(GLOB SERIALIZERS_S_CPP_FILES ../src/serializers/schema_dependent/*.cpp)
|
||||
set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES})
|
||||
|
||||
add_library(Serializers_ifc2x3 STATIC ${SERIALIZERS_S_FILES})
|
||||
add_library(Serializers_ifc4 STATIC ${SERIALIZERS_S_FILES})
|
||||
|
||||
set_target_properties(Serializers_ifc2x3 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc2x3 ${CONVERT_PRECISION}")
|
||||
# TODO: Detect based on IfcSchema
|
||||
set_target_properties(Serializers_ifc4 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc4 -DUSE_IFC4 ${CONVERT_PRECISION}")
|
||||
|
||||
TARGET_LINK_LIBRARIES(Serializers_ifc2x3 IfcGeom ${OPENCASCADE_LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(Serializers_ifc4 IfcGeom ${OPENCASCADE_LIBRARIES})
|
||||
|
||||
add_library(Serializers ${SERIALIZERS_FILES})
|
||||
set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}")
|
||||
|
||||
TARGET_LINK_LIBRARIES(Serializers Serializers_ifc2x3 Serializers_ifc4)
|
||||
|
||||
# IfcConvert
|
||||
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
|
||||
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
|
||||
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
|
||||
ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES})
|
||||
set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}")
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
|
||||
|
||||
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}")
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS IfcConvert
|
||||
ARCHIVE DESTINATION ${LIBDIR}
|
||||
LIBRARY DESTINATION ${LIBDIR}
|
||||
RUNTIME DESTINATION ${BINDIR}
|
||||
)
|
||||
|
||||
TARGET_LINK_LIBRARIES (IfcGeomServer IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset)
|
||||
endif(BUILD_CONVERT)
|
||||
|
||||
# Build python wrapper using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
# IfcGeomServer
|
||||
if(BUILD_GEOMSERVER)
|
||||
|
||||
# Build IfcParseExamples using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/examples examples)
|
||||
file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp)
|
||||
file(GLOB H_FILES ../src/ifcgeomserver/*.h)
|
||||
set(SOURCE_FILES ${CPP_FILES} ${H_FILES})
|
||||
ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
|
||||
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
|
||||
|
||||
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
|
||||
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS IfcGeomServer
|
||||
ARCHIVE DESTINATION ${LIBDIR}
|
||||
LIBRARY DESTINATION ${LIBDIR}
|
||||
RUNTIME DESTINATION ${BINDIR}
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
IF(BUILD_IFCPYTHON)
|
||||
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
ENDIF()
|
||||
|
||||
IF(BUILD_EXAMPLES)
|
||||
ADD_SUBDIRECTORY(../src/examples examples)
|
||||
ENDIF()
|
||||
|
||||
IF(BUILD_IFCMAX)
|
||||
ADD_SUBDIRECTORY(../src/ifcmax ifcmax)
|
||||
ENDIF()
|
||||
|
||||
# CMake installation targets
|
||||
SET(include_files_geom
|
||||
../src/ifcgeom/IfcGeom.h
|
||||
../src/ifcgeom/IfcGeomElement.h
|
||||
../src/ifcgeom/IfcGeomIterator.h
|
||||
../src/ifcgeom/IfcGeomIteratorSettings.h
|
||||
../src/ifcgeom/IfcGeomMaterial.h
|
||||
../src/ifcgeom/IfcGeomRenderStyles.h
|
||||
../src/ifcgeom/IfcGeomRepresentation.h
|
||||
../src/ifcgeom/IfcRegister.h
|
||||
../src/ifcgeom/IfcRegisterConvertCurve.h
|
||||
../src/ifcgeom/IfcRegisterConvertFace.h
|
||||
../src/ifcgeom/IfcRegisterConvertShape.h
|
||||
../src/ifcgeom/IfcRegisterConvertShapes.h
|
||||
../src/ifcgeom/IfcRegisterConvertWire.h
|
||||
../src/ifcgeom/IfcRegisterCreateCache.h
|
||||
../src/ifcgeom/IfcRegisterDef.h
|
||||
../src/ifcgeom/IfcRegisterGeomHeader.h
|
||||
../src/ifcgeom/IfcRegisterIsShapeCollection.h
|
||||
../src/ifcgeom/IfcRegisterPurgeCache.h
|
||||
../src/ifcgeom/IfcRegisterUndef.h
|
||||
../src/ifcgeom/IfcRepresentationShapeItem.h
|
||||
INSTALL(FILES ${IFCPARSE_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcparse
|
||||
)
|
||||
SET(include_files_parse
|
||||
../src/ifcparse/Ifc2x3-latebound.h
|
||||
../src/ifcparse/Ifc2x3.h
|
||||
../src/ifcparse/Ifc2x3enum.h
|
||||
../src/ifcparse/Ifc4-latebound.h
|
||||
../src/ifcparse/Ifc4.h
|
||||
../src/ifcparse/Ifc4enum.h
|
||||
../src/ifcparse/IfcCharacterDecoder.h
|
||||
../src/ifcparse/IfcEntityDescriptor.h
|
||||
../src/ifcparse/IfcException.h
|
||||
../src/ifcparse/IfcFile.h
|
||||
../src/ifcparse/IfcHierarchyHelper.h
|
||||
../src/ifcparse/IfcLateBoundEntity.h
|
||||
../src/ifcparse/IfcParse.h
|
||||
../src/ifcparse/IfcSIPrefix.h
|
||||
../src/ifcparse/IfcSpfHeader.h
|
||||
../src/ifcparse/IfcSpfStream.h
|
||||
../src/ifcparse/IfcUtil.h
|
||||
../src/ifcparse/IfcWritableEntity.h
|
||||
../src/ifcparse/IfcWrite.h
|
||||
../src/ifcparse/SharedPointer.h
|
||||
|
||||
INSTALL(TARGETS IfcParse
|
||||
ARCHIVE DESTINATION ${LIBDIR}
|
||||
LIBRARY DESTINATION ${LIBDIR}
|
||||
RUNTIME DESTINATION ${BINDIR}
|
||||
)
|
||||
INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom)
|
||||
INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse)
|
||||
INSTALL(TARGETS IfcConvert DESTINATION bin)
|
||||
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
|
||||
|
||||
if(BUILD_IFCGEOM)
|
||||
INSTALL(FILES ${IFCGEOM_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom
|
||||
)
|
||||
|
||||
INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic
|
||||
)
|
||||
|
||||
INSTALL(TARGETS IfcGeom_ifc2x3 IfcGeom_ifc4 IfcGeom
|
||||
ARCHIVE DESTINATION ${LIBDIR}
|
||||
LIBRARY DESTINATION ${LIBDIR}
|
||||
RUNTIME DESTINATION ${BINDIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_CONVERT)
|
||||
INSTALL(TARGETS Serializers Serializers_ifc2x3 Serializers_ifc4
|
||||
ARCHIVE DESTINATION ${LIBDIR}
|
||||
LIBRARY DESTINATION ${LIBDIR}
|
||||
RUNTIME DESTINATION ${BINDIR}
|
||||
)
|
||||
|
||||
INSTALL(FILES ${SERIALIZERS_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/serializers/
|
||||
)
|
||||
|
||||
INSTALL(FILES ${SERIALIZERS_S_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/serializers/schema_dependent
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
mkdir build && cd build
|
||||
|
||||
REM Remove dot from PY_VER for use in library name
|
||||
REM From https://github.com/tpaviot/pythonocc-core/blob/master/ci/conda/bld.bat
|
||||
set MY_PY_VER=%PY_VER:.=%
|
||||
|
||||
cmake -G "NMake Makefiles" ^
|
||||
-DCMAKE_INSTALL_PREFIX="%LIBRARY_PREFIX%" ^
|
||||
-DCMAKE_BUILD_TYPE=Release ^
|
||||
-DCMAKE_PREFIX_PATH="%LIBRARY_PREFIX%" ^
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH="%LIBRARY_PREFIX%" ^
|
||||
-DPYTHON_EXECUTABLE="%PYTHON%" ^
|
||||
-DPYTHON_INCLUDE_DIR="%PREFIX%"/include ^
|
||||
-DPYTHON_LIBRARY="%PREFIX%"/libs/python%MY_PY_VER%.lib ^
|
||||
-DBOOST_LIBRARYDIR="%LIBRARY_PREFIX%\lib" ^
|
||||
-DBOOST_INCLUDEDIR="%LIBRARY_PREFIX%\include" ^
|
||||
-DOCC_INCLUDE_DIR="%LIBRARY_PREFIX%\include\oce" ^
|
||||
-DOCC_LIBRARY_DIR="%LIBRARY_PREFIX%\lib" ^
|
||||
-DCOLLADA_SUPPORT=Off ^
|
||||
-DBUILD_EXAMPLES=Off ^
|
||||
-DBUILD_GEOMSERVER=Off ^
|
||||
-DBUILD_CONVERT=Off ^
|
||||
../cmake
|
||||
|
||||
if errorlevel 1 exit 1
|
||||
|
||||
cmake --build . --target INSTALL --config Release
|
||||
|
||||
if errorlevel 1 exit 1
|
||||
@@ -0,0 +1,34 @@
|
||||
# From https://github.com/tpaviot/pythonocc-core/blob/master/ci/conda/build.sh
|
||||
if [ "$PY3K" == "1" ]; then
|
||||
MY_PY_VER="${PY_VER}m"
|
||||
else
|
||||
MY_PY_VER="${PY_VER}"
|
||||
fi
|
||||
|
||||
if [ `uname` == Darwin ]; then
|
||||
PY_LIB="libpython${MY_PY_VER}.dylib"
|
||||
export CFLAGS="$CFLAGS -Wl,-flat_namespace,-undefined,suppress"
|
||||
export CXXFLAGS="$CXXFLAGS -Wl,-flat_namespace,-undefined,suppress"
|
||||
export LDFLAGS="$LDFLAGS -Wl,-flat_namespace,-undefined,suppress"
|
||||
else
|
||||
PY_LIB="libpython${MY_PY_VER}.so"
|
||||
fi
|
||||
|
||||
mkdir build && cd build
|
||||
|
||||
cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=$PREFIX \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH=$PREFIX \
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=$PREFIX \
|
||||
-DOCC_INCLUDE_DIR=$PREFIX/include/oce \
|
||||
-DOCC_LIBRARY_DIR=$PREFIX/lib \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH=$PYTHON \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=$PREFIX/include/python$MY_PY_VER \
|
||||
-DPYTHON_LIBRARY:FILEPATH=$PREFIX/lib/${PY_LIB} \
|
||||
-DCOLLADA_SUPPORT=Off \
|
||||
../cmake
|
||||
|
||||
make -j$CPU_COUNT _ifcopenshell_wrapper
|
||||
cd ifcwrap
|
||||
make install/local
|
||||
@@ -0,0 +1,36 @@
|
||||
package:
|
||||
name: ifcopenshell
|
||||
version: "0.6.0a1"
|
||||
|
||||
source:
|
||||
git_rev: "v0.6.0a1"
|
||||
git_url: https://github.com/IfcOpenShell/IfcOpenShell
|
||||
|
||||
build:
|
||||
number: 0
|
||||
features:
|
||||
- vc9 # [win and py27]
|
||||
- vc10 # [win and py34]
|
||||
- vc14 # [win and py35]
|
||||
- vc14 # [win and py36]
|
||||
|
||||
requirements:
|
||||
build:
|
||||
- gcc # [osx]
|
||||
- make
|
||||
- python
|
||||
- oce ==0.18.3
|
||||
- cmake
|
||||
- swig >=3.0.9
|
||||
- libboost
|
||||
- icu
|
||||
run:
|
||||
- libgcc # [osx]
|
||||
- python
|
||||
- oce ==0.18.3
|
||||
- libboost
|
||||
- icu
|
||||
|
||||
about:
|
||||
home: http://ifcopenshell.org
|
||||
license: LGPL
|
||||
@@ -0,0 +1,763 @@
|
||||
#!/usr/bin/python
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# #
|
||||
# This script builds IfcOpenShell and its dependencies #
|
||||
# #
|
||||
# Prerequisites for this script to function correctly: #
|
||||
# * git * bzip2 * tar * c(++) compilers * yacc * autoconf #
|
||||
# #
|
||||
# if building with USE_OCCT additionally: #
|
||||
# * freetype * glx.h #
|
||||
# #
|
||||
# if building with -shared #
|
||||
# * libgl1-mesa-dev libxext-dev libxmu-dev libxmu-headers libxi-dev #
|
||||
# #
|
||||
# for python37 to install correctly additionally: #
|
||||
# * libffi(-dev[el]) #
|
||||
# #
|
||||
# on debian 7.8 these can be obtained with: #
|
||||
# $ apt-get install git gcc g++ autoconf bison bzip2 #
|
||||
# libfreetype6-dev mesa-common-dev libffi-dev #
|
||||
# #
|
||||
# on ubuntu 14.04: #
|
||||
# $ apt-get install git gcc g++ autoconf bison make #
|
||||
# libfreetype6-dev mesa-common-dev libffi-dev #
|
||||
# #
|
||||
# on OS X El Capitan with homebrew: #
|
||||
# $ brew install git bison autoconf automake freetype libffi #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import subprocess as sp
|
||||
import shutil
|
||||
import time
|
||||
import tarfile
|
||||
import multiprocessing
|
||||
import urllib
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.INFO)
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.INFO)
|
||||
logger.addHandler(ch)
|
||||
|
||||
PROJECT_NAME="IfcOpenShell"
|
||||
OCE_VERSION="0.18"
|
||||
# OCCT_VERSION="7.1.0"
|
||||
# OCCT_HASH="89aebde"
|
||||
PYTHON_VERSIONS=["2.7.16", "3.2.6", "3.3.6", "3.4.6", "3.5.3", "3.6.2", "3.7.3"]
|
||||
# OCCT_VERSION="7.2.0"
|
||||
# OCCT_HASH="88af392"
|
||||
OCCT_VERSION="7.3.0p3"
|
||||
BOOST_VERSION="1.59.0"
|
||||
PCRE_VERSION="8.39"
|
||||
LIBXML_VERSION="2.9.3"
|
||||
CMAKE_VERSION="3.4.1"
|
||||
SWIG_VERSION="3.0.12"
|
||||
|
||||
# binaries
|
||||
cp="cp"
|
||||
bash="bash"
|
||||
uname="uname"
|
||||
git="git"
|
||||
bunzip2="bunzip2"
|
||||
tar="tar"
|
||||
cc="cc"
|
||||
cplusplus="c++"
|
||||
autoconf="autoconf"
|
||||
automake="automake"
|
||||
yacc="yacc"
|
||||
make="make"
|
||||
date = "date"
|
||||
curl="curl"
|
||||
wget="wget"
|
||||
strip="strip"
|
||||
|
||||
# Helper function for coloured printing
|
||||
|
||||
NO_COLOR="\033[0m" # <ref>http://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux</ref>
|
||||
BLACK_ON_WHITE="\033[0;30;107m"
|
||||
RED="\033[31m"
|
||||
GREEN="\033[32m"
|
||||
YELLOW="\033[33m"
|
||||
MAGENTA="\033[35m"
|
||||
|
||||
def cecho(message, color=NO_COLOR):
|
||||
"""Logs message `message` in color `color`."""
|
||||
logger.info("%s%s\033[0m" % (color, message))
|
||||
|
||||
def which(cmd):
|
||||
for path in os.environ["PATH"].split(":"):
|
||||
if os.path.exists(path) and cmd in os.listdir(path):
|
||||
return cmd
|
||||
return None
|
||||
|
||||
def get_os():
|
||||
ret_value = sp.check_output([uname, "-s"]).strip()
|
||||
return ret_value
|
||||
|
||||
# Set defaults for missing empty environment variables
|
||||
|
||||
USE_OCCT = os.environ.get("USE_OCCT", "true").lower() == "true"
|
||||
|
||||
TOOLSET = None
|
||||
if get_os() == "Darwin":
|
||||
# C++11 features used in OCCT 7+ need a more recent stdlib
|
||||
TOOLSET = "10.9" if USE_OCCT else "10.6"
|
||||
|
||||
try:
|
||||
IFCOS_NUM_BUILD_PROCS = os.environ["IFCOS_NUM_BUILD_PROCS"]
|
||||
except KeyError:
|
||||
IFCOS_NUM_BUILD_PROCS=multiprocessing.cpu_count() + 1
|
||||
|
||||
try:
|
||||
TARGET_ARCH = os.environ["TARGET_ARCH"]
|
||||
except KeyError:
|
||||
TARGET_ARCH = sp.check_output([uname, "-m"]).strip()
|
||||
|
||||
CMAKE_DIR=os.path.realpath(os.path.join("..", "cmake"))
|
||||
|
||||
try:
|
||||
DEPS_DIR = os.environ["DEPS_DIR"]
|
||||
except KeyError:
|
||||
path = ["..", "build", sp.check_output(uname).strip(), TARGET_ARCH]
|
||||
if TOOLSET:
|
||||
path.append(TOOLSET)
|
||||
DEPS_DIR = os.path.realpath(os.path.join(*path))
|
||||
|
||||
if not os.path.exists(DEPS_DIR):
|
||||
os.makedirs(DEPS_DIR)
|
||||
|
||||
try:
|
||||
BUILD_CFG=os.environ["BUILD_CFG"]
|
||||
except KeyError:
|
||||
BUILD_CFG="RelWithDebInfo"
|
||||
|
||||
|
||||
# Print build configuration information
|
||||
|
||||
cecho ("""This script fetches and builds %s and its dependencies
|
||||
""" % (PROJECT_NAME,), BLACK_ON_WHITE)
|
||||
cecho("""Script configuration:
|
||||
|
||||
""", GREEN)
|
||||
cecho("""* Target Architecture = %s""" % (TARGET_ARCH,), MAGENTA)
|
||||
cecho(" - Whether 32-bit (i686) or 64-bit (x86_64) will be built.")
|
||||
cecho("""* USE_OCCT = %r""" % (USE_OCCT,), MAGENTA)
|
||||
if USE_OCCT:
|
||||
cecho(" - Compiling against official Open Cascade")
|
||||
else:
|
||||
cecho(" - Compiling against Open Cascade Community Edition")
|
||||
cecho("* Dependency Directory = %s" % (DEPS_DIR,), MAGENTA)
|
||||
cecho(" - The directory where %s dependencies are installed." % (PROJECT_NAME,))
|
||||
cecho("* Build Config Type = %s" % (BUILD_CFG,), MAGENTA)
|
||||
cecho(""" - The used build configuration type for the dependencies.
|
||||
Defaults to RelWithDebInfo if not specified.""")
|
||||
|
||||
if BUILD_CFG == "MinSizeRel":
|
||||
cecho(" WARNING: MinSizeRel build can suffer from a significant performance loss.", RED)
|
||||
|
||||
cecho("* IFCOS_NUM_BUILD_PROCS = %s" % (IFCOS_NUM_BUILD_PROCS,), MAGENTA)
|
||||
cecho(""" - How many compiler processes may be run in parallel.
|
||||
""")
|
||||
|
||||
dependency_tree = {
|
||||
'IfcParse': ('boost', 'libxml2'),
|
||||
'IfcGeom': ('IfcParse', 'occ'),
|
||||
'IfcConvert': ('IfcGeom', 'OpenCOLLADA', 'json'),
|
||||
'OpenCOLLADA': ('libxml2', 'pcre'),
|
||||
'IfcGeomServer': ('IfcGeom',),
|
||||
'IfcOpenShell-Python': ('python', 'swig', 'IfcGeom'),
|
||||
'swig': ('pcre',),
|
||||
'boost': (),
|
||||
'libxml2': (),
|
||||
'python': (),
|
||||
'swig': (),
|
||||
'occ': (),
|
||||
'pcre': (),
|
||||
'json': ()
|
||||
}
|
||||
|
||||
def v(dep):
|
||||
yield dep
|
||||
for d in dependency_tree[dep]:
|
||||
for x in v(d):
|
||||
yield x
|
||||
|
||||
tgts = [s for s in sys.argv[1:] if not s.startswith("-")]
|
||||
flags = set(s for s in sys.argv[1:] if s.startswith("-"))
|
||||
|
||||
BUILD_STATIC = not "-shared" in flags
|
||||
ENABLE_FLAG = "--enable-static" if BUILD_STATIC else "--enable-shared"
|
||||
DISABLE_FLAG = "--disable-shared" if BUILD_STATIC else "--disable-static"
|
||||
LINK_TYPE = "static" if BUILD_STATIC else "shared"
|
||||
LINK_TYPE_UCFIRST = LINK_TYPE[0].upper() + LINK_TYPE[1:]
|
||||
LIBRARY_EXT = "a" if BUILD_STATIC else "so"
|
||||
PIC = "-fPIC" if BUILD_STATIC else ""
|
||||
|
||||
if len(tgts):
|
||||
targets = set(sum((list(v(target)) for target in tgts), []))
|
||||
else:
|
||||
targets = set(dependency_tree.keys())
|
||||
|
||||
print("Building:", *sorted(targets, key=lambda t: len(list(v(t)))))
|
||||
|
||||
# Check that required tools are in PATH
|
||||
|
||||
for cmd in [git, bunzip2, tar, cc, cplusplus, autoconf, automake, yacc, make, "patch"]:
|
||||
if which(cmd) is None:
|
||||
raise ValueError("Required tool '%s' not installed or not added to PATH" % (cmd,))
|
||||
|
||||
# identifiers for the download tool (could be less memory consuming as ints, but are more verbose as strings)
|
||||
download_tool_curl="curl"
|
||||
download_tool_wget="wget"
|
||||
download_tool_git = "git"
|
||||
|
||||
if which(wget) != None:
|
||||
download_tool_default = download_tool_wget
|
||||
elif which(curl) != None:
|
||||
download_tool_default = download_tool_curl
|
||||
else:
|
||||
raise ValueError("No download application found, tried: curl, wget")
|
||||
|
||||
CURL = ["curl", "-sL"]
|
||||
WGET= ["wget", "-q", "--no-check-certificate"]
|
||||
|
||||
# Create log directory and file
|
||||
|
||||
log_dir = os.path.join(DEPS_DIR, "logs")
|
||||
if not os.path.exists(log_dir):
|
||||
os.makedirs(log_dir)
|
||||
LOG_FILE="%s.log" % (os.path.join(log_dir, sp.check_output([date, "+%Y%m%d"]).strip()),)
|
||||
if not os.path.exists(LOG_FILE):
|
||||
open(LOG_FILE, "w").close()
|
||||
logger.info("using command log file '%s'" % (LOG_FILE,))
|
||||
|
||||
def run(cmds, cwd=None):
|
||||
|
||||
"""
|
||||
Wraps `subprocess.Popen.communicate()` and logs the command being executed,
|
||||
sets up logging `stderr` to `LOG_FILE` (in append mode) and returns stdout
|
||||
with leading and trailing whitespace removed.
|
||||
"""
|
||||
|
||||
logger.debug("running command %r in directory %r" % (" ".join(cmds), cwd))
|
||||
log_file_handle = open(LOG_FILE, "a")
|
||||
proc = sp.Popen(cmds, cwd=cwd, stdout=sp.PIPE, stderr=sp.PIPE)
|
||||
stdout, stderr = proc.communicate()
|
||||
log_file_handle.write(stdout)
|
||||
log_file_handle.write(stderr)
|
||||
log_file_handle.close()
|
||||
logger.debug("command returned %r" % proc.returncode)
|
||||
|
||||
if proc.returncode != 0:
|
||||
print("-" * 70)
|
||||
print(stderr)
|
||||
print("-" * 70)
|
||||
raise Exception("Command `%s` returned exit code %d" % (" ".join(cmds), proc.returncode))
|
||||
|
||||
return stdout.strip()
|
||||
|
||||
BOOST_VERSION_UNDERSCORE=BOOST_VERSION.replace(".", "_")
|
||||
CMAKE_VERSION_2=CMAKE_VERSION[:CMAKE_VERSION.rindex('.')]
|
||||
|
||||
OCE_LOCATION="https://github.com/tpaviot/oce/archive/OCE-%s.tar.gz" % (OCE_VERSION,)
|
||||
BOOST_LOCATION="http://downloads.sourceforge.net/project/boost/boost/%s/boost_%s.tar.bz2" % (BOOST_VERSION, BOOST_VERSION_UNDERSCORE)
|
||||
OPENCOLLADA_LOCATION="https://github.com/KhronosGroup/OpenCOLLADA.git"
|
||||
#OPENCOLLADA_COMMIT="f99d59e73e565a41715eaebc00c7664e1ee5e628"
|
||||
OPENCOLLADA_COMMIT="v1.6.63"
|
||||
|
||||
# Helper functions
|
||||
|
||||
def run_autoconf(arg1, configure_args, cwd):
|
||||
configure_path = os.path.realpath(os.path.join(cwd, "..", "configure"))
|
||||
if not os.path.exists(configure_path):
|
||||
run([bash, "./autogen.sh"], cwd=os.path.realpath(os.path.join(cwd, ".."))) # only run autogen.sh in the directory it is located and use cwd to achieve that in order to not mess up things
|
||||
# Using `sh` over `bash` fixes issues with building swig
|
||||
run(["/bin/sh", "../configure"]+configure_args+["--prefix=%s" % (os.path.realpath("%s/install/%s" % (DEPS_DIR, arg1)),)], cwd=cwd)
|
||||
|
||||
def run_cmake(arg1, cmake_args, cmake_dir=None, cwd=None):
|
||||
if cmake_dir is None:
|
||||
P=".."
|
||||
else:
|
||||
P=cmake_dir
|
||||
cmake_path= os.path.join(DEPS_DIR, "install", "cmake-%s" % (CMAKE_VERSION,), "bin", "cmake")
|
||||
run([cmake_path, P]+cmake_args+["-DCMAKE_BUILD_TYPE=%s" % (BUILD_CFG,)], cwd=cwd)
|
||||
|
||||
def git_clone(clone_url, target_dir, revision=None):
|
||||
"""Lazily clones the `git` repository denoted by `clone_url` into
|
||||
`target_dir`, i.e. skips cloning if `target_dir` exists (naively assumes
|
||||
that a working clone exists there) and optionally checks out a revision
|
||||
`revision` after cloning or in the existing clone if `revision` is not
|
||||
`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])
|
||||
else:
|
||||
logger.info("directory '%s' exists, skipping cloning" % (target_dir,))
|
||||
if revision != None:
|
||||
run([git, "checkout", revision], cwd=target_dir)
|
||||
|
||||
def build_dependency(name, mode, build_tool_args, download_url, download_name, download_tool=download_tool_default, revision=None, patch=None, additional_files={}, no_append_name=False):
|
||||
"""Handles building of dependencies with different tools (which are
|
||||
distinguished with the `mode` argument. `build_tool_args` is expected to be
|
||||
a list which is necessary in order to not mess up quoting of compiler and
|
||||
linker flags."""
|
||||
check_dir = os.path.join(DEPS_DIR, "install", name)
|
||||
if os.path.exists(check_dir):
|
||||
logger.info( "Found existing %s, skipping" % (name,))
|
||||
return
|
||||
build_dir = os.path.join(DEPS_DIR, "build")
|
||||
if not os.path.exists(build_dir):
|
||||
os.makedirs(build_dir)
|
||||
|
||||
logger.info("\rFetching %s... " % (name,))
|
||||
|
||||
if download_tool == download_tool_curl or download_tool == download_tool_wget:
|
||||
if no_append_name:
|
||||
url = download_url
|
||||
else:
|
||||
url = os.path.join(download_url, download_name)
|
||||
|
||||
if download_tool == download_tool_curl:
|
||||
download_path = os.path.join(build_dir, download_name)
|
||||
if not os.path.exists(download_path):
|
||||
run(CURL + ["-o", download_name, url], cwd=build_dir)
|
||||
else:
|
||||
logger.info("Download '%s' already exists, assuming it's an undamaged download and that it has been extracted if possible, skipping" % (download_path,))
|
||||
elif download_tool == download_tool_wget:
|
||||
download_path = os.path.join(build_dir, download_name)
|
||||
if not os.path.exists(download_path):
|
||||
run(WGET + ["-O", download_name, url], cwd=build_dir)
|
||||
else:
|
||||
logger.info("Download '%s' already exists, assuming it's an undamaged download and that it has been extracted if possible, skipping" % (download_path,))
|
||||
elif download_tool == download_tool_git:
|
||||
git_clone(download_url, target_dir=os.path.join(build_dir, download_name), revision=revision)
|
||||
else:
|
||||
raise ValueError("download tool '%s' is not supported" % (download_tool,))
|
||||
download_dir = os.path.join(build_dir, download_name)
|
||||
|
||||
if os.path.isdir(download_dir):
|
||||
extract_dir_name=download_name
|
||||
extract_dir = os.path.join(build_dir, extract_dir_name)
|
||||
else:
|
||||
download_tarfile_path = os.path.join(build_dir, download_name)
|
||||
if download_name.endswith(".tar.gz") or download_name.endswith(".tgz"):
|
||||
compr = "gz"
|
||||
elif download_name.endswith(".tar.bz2"):
|
||||
compr = "bz2"
|
||||
else:
|
||||
raise RuntimeError("fix source for new download type")
|
||||
download_tarfile = tarfile.open(name=download_tarfile_path, mode="r:%s" % (compr,))
|
||||
extract_dir_name= os.path.commonprefix(download_tarfile.getnames()) # tarfile seriously doesn't have a function to retrieve the root directory more easily
|
||||
#run([tar, "--exclude=\"*/*\"", "-tf", download_name], cwd=build_dir).strip() no longer works
|
||||
if extract_dir_name is None:
|
||||
extract_dir_name= run([bash, "-c", "tar -tf %s 2> /dev/null | head -n 1 | cut -f1 -d /" % (download_name,)], cwd=build_dir)
|
||||
extract_dir = os.path.join(build_dir, extract_dir_name)
|
||||
if not os.path.exists(extract_dir):
|
||||
run([tar, "-xf", download_name], cwd=build_dir)
|
||||
|
||||
for path, url in additional_files.items():
|
||||
if not os.path.exists(path):
|
||||
urllib.urlretrieve(url, os.path.join(extract_dir, path))
|
||||
|
||||
if patch is not None:
|
||||
patch_abs = os.path.abspath(os.path.join(os.path.dirname(__file__), patch))
|
||||
if os.path.exists(patch_abs):
|
||||
try: run(["patch", "-p1", "--batch", "--forward", "-i", patch_abs], cwd=extract_dir)
|
||||
except Exception as e:
|
||||
# Assert that the patch has already been applied
|
||||
run(["patch", "-p1", "--batch", "--reverse", "--dry-run", "-i", patch_abs], cwd=extract_dir)
|
||||
|
||||
if mode != "bjam":
|
||||
extract_build_dir = os.path.join(extract_dir, "build")
|
||||
if os.path.exists(extract_build_dir):
|
||||
shutil.rmtree(extract_build_dir)
|
||||
os.makedirs(extract_build_dir)
|
||||
|
||||
logger.info("\rConfiguring %s..." % (name,))
|
||||
if mode == "autoconf":
|
||||
run_autoconf(name, build_tool_args, cwd=extract_build_dir)
|
||||
elif mode == "cmake":
|
||||
run_cmake(name, build_tool_args, cwd=extract_build_dir)
|
||||
else:
|
||||
raise ValueError()
|
||||
logger.info("\rBuilding %s... " % (name,))
|
||||
run([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,)], cwd=extract_build_dir)
|
||||
logger.info( "\rInstalling %s... " % (name,))
|
||||
run([make, "install"], cwd=extract_build_dir)
|
||||
logger.info( "\rInstalled %s \n" % (name,))
|
||||
else:
|
||||
logger.info( "\rConfiguring %s..." % (name,))
|
||||
run([bash, "./bootstrap.sh"], cwd=extract_dir)
|
||||
logger.info("\rBuilding %s... " % (name,))
|
||||
run(["./b2", "-j%s" % (IFCOS_NUM_BUILD_PROCS,)]+build_tool_args, cwd=extract_dir)
|
||||
logger.info("\rInstalling %s... " % (name,))
|
||||
shutil.copytree(os.path.join(extract_dir, "boost"), os.path.join(DEPS_DIR, "install", "boost-%s" % BOOST_VERSION, "boost"))
|
||||
logger.info("\rInstalled %s \n" % (name,))
|
||||
|
||||
cecho("Collecting dependencies:", GREEN)
|
||||
|
||||
# Set compiler flags for 32bit builds on 64bit system
|
||||
# TODO: This is untested
|
||||
|
||||
ADDITIONAL_ARGS=[]
|
||||
BOOST_ADDRESS_MODEL=[]
|
||||
if TARGET_ARCH == "i686" and run([uname, "-m"]).strip() == "x86_64":
|
||||
ADDITIONAL_ARGS=["-m32", "-arch i386"]
|
||||
BOOST_ADDRESS_MODEL=["architecture=x86", "address-model=32"]
|
||||
|
||||
if get_os() == "Darwin":
|
||||
ADDITIONAL_ARGS=["-mmacosx-version-min=%s" % TOOLSET]+ADDITIONAL_ARGS
|
||||
|
||||
# If the linker supports GC sections, set it up to reduce binary file size
|
||||
# -fPIC is required for the shared libraries to work
|
||||
|
||||
CXXFLAGS=os.environ.get("CXXFLAGS", "")
|
||||
CFLAGS=os.environ.get("CFLAGS", "")
|
||||
LDFLAGS=os.environ.get("LDFLAGS", "")
|
||||
|
||||
if sp.call([bash, "-c", "ld --gc-sections 2>&1 | grep -- --gc-sections &> /dev/null"]) != 0:
|
||||
CXXFLAGS_MINIMAL="%s %s %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
|
||||
CFLAGS_MINIMAL="%s %s %s" % (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
|
||||
if BUILD_STATIC:
|
||||
CXXFLAGS="%s %s -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
|
||||
CFLAGS="%s %s -fdata-sections -ffunction-sections -fvisibility=hidden %s"% (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
|
||||
else:
|
||||
CXXFLAGS=CXXFLAGS_MINIMAL
|
||||
CFLAGS=CFLAGS_MINIMAL
|
||||
LDFLAGS="%s -Wl,--gc-sections %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
else:
|
||||
CXXFLAGS_MINIMAL="%s %s %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
|
||||
CFLAGS_MINIMAL="%s %s %s" % (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
|
||||
if BUILD_STATIC:
|
||||
CXXFLAGS="%s %s -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
|
||||
CFLAGS="%s %s -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
|
||||
else:
|
||||
CXXFLAGS=CXXFLAGS_MINIMAL
|
||||
CFLAGS=CFLAGS_MINIMAL
|
||||
LDFLAGS="%s %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
|
||||
os.environ["CXXFLAGS"] = CXXFLAGS
|
||||
os.environ["CFLAGS"] = CFLAGS
|
||||
os.environ["LDFLAGS"] = LDFLAGS
|
||||
|
||||
# Some dependencies need a more recent CMake version than most distros provide
|
||||
build_dependency(name="cmake-%s" % (CMAKE_VERSION,), mode="autoconf", build_tool_args=[], download_url="https://cmake.org/files/v%s" % (CMAKE_VERSION_2,), download_name="cmake-%s.tar.gz" % (CMAKE_VERSION,))
|
||||
|
||||
# Extract compiler flags from CMake to harmonize settings with other autoconf dependencies
|
||||
CMAKE_FLAG_EXTRACT_DIR="ifcopenshell_cmake_test_%s" % (time.time(),)
|
||||
# was sp.check_output([bash, "-c", "cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | head -c 32"]), in bash script, unclear what the exact required format is and whether it's needed
|
||||
if os.path.exists(CMAKE_FLAG_EXTRACT_DIR):
|
||||
shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR)
|
||||
os.makedirs(CMAKE_FLAG_EXTRACT_DIR)
|
||||
BUILD_CFG_UPPER=BUILD_CFG.upper()
|
||||
for FL in ["C", "CXX"]:
|
||||
run([bash, "-c", """echo "
|
||||
message(\"\${CMAKE_%s_FLAGS_%s}\")
|
||||
" > CMakeLists.txt""" % (FL, BUILD_CFG_UPPER)], cwd=CMAKE_FLAG_EXTRACT_DIR)
|
||||
FL="%sFLAGS" % (FL,)
|
||||
FLM="%sFLAGS_MINIMAL" % (FL,)
|
||||
# @TODO: bash code unclear
|
||||
# exec("%sFLAGS=%s" % (FL, sp.check_output([os.path.join(DEPS_DIR, "install", "cmake-%s" % (CMAKE_VERSION,), "bin", "cmake"), "."
|
||||
# declare ${FL}FLAGS_MINIMAL="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null` ${!FLM}"
|
||||
shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR)
|
||||
|
||||
if "json" in targets:
|
||||
json_url = "https://github.com/nlohmann/json/releases/download/v3.6.1/json.hpp"
|
||||
json_install_path = "{DEPS_DIR}/install/json/nlohmann/json.hpp".format(**locals())
|
||||
if not os.path.exists(json_install_path):
|
||||
os.makedirs(os.path.dirname(json_install_path))
|
||||
urllib.urlretrieve(json_url, json_install_path)
|
||||
|
||||
if "pcre" in targets:
|
||||
build_dependency(
|
||||
name="pcre-{PCRE_VERSION}".format(**locals()),
|
||||
mode="autoconf",
|
||||
build_tool_args=[DISABLE_FLAG],
|
||||
download_url="https://downloads.sourceforge.net/project/pcre/pcre/{PCRE_VERSION}/".format(**locals()),
|
||||
download_name="pcre-{PCRE_VERSION}.tar.bz2".format(**locals())
|
||||
)
|
||||
|
||||
# An issue exists with swig-1.3 and python >= 3.2
|
||||
# Therefore, build a recent copy from source
|
||||
if "swig" in targets:
|
||||
build_dependency(
|
||||
name="swig",
|
||||
mode="autoconf",
|
||||
build_tool_args=["--with-pcre-prefix={DEPS_DIR}/install/pcre-{PCRE_VERSION}".format(**locals())],
|
||||
download_url="https://github.com/swig/swig.git",
|
||||
download_name="swig",
|
||||
download_tool=download_tool_git,
|
||||
revision="rel-{SWIG_VERSION}".format(**locals())
|
||||
)
|
||||
|
||||
if USE_OCCT and "occ" in targets:
|
||||
build_dependency(
|
||||
name="occt-{OCCT_VERSION}".format(**locals()),
|
||||
mode="cmake",
|
||||
build_tool_args=[
|
||||
"-DINSTALL_DIR={DEPS_DIR}/install/occt-{OCCT_VERSION}".format(**locals()),
|
||||
"-DBUILD_LIBRARY_TYPE={LINK_TYPE_UCFIRST}".format(**locals()),
|
||||
"-DBUILD_MODULE_Draw=0",
|
||||
],
|
||||
download_url = "https://git.dev.opencascade.org/repos/occt.git",
|
||||
download_name = "occt",
|
||||
download_tool=download_tool_git,
|
||||
patch="./patches/occt/enable-exception-handling.patch",
|
||||
revision="V" + OCCT_VERSION.replace('.', '_')
|
||||
)
|
||||
elif "occ" in targets:
|
||||
build_dependency(
|
||||
name="oce-{OCE_VERSION}".format(**locals()),
|
||||
mode="cmake",
|
||||
build_tool_args=[
|
||||
"-DOCE_DISABLE_TKSERVICE_FONT=ON",
|
||||
"-DOCE_TESTING=OFF",
|
||||
"-DOCE_BUILD_SHARED_LIB=OFF",
|
||||
"-DOCE_DISABLE_X11=ON",
|
||||
"-DOCE_VISUALISATION=OFF",
|
||||
"-DOCE_OCAF=OFF",
|
||||
"-DOCE_INSTALL_PREFIX={DEPS_DIR}/install/oce-{OCE_VERSION}".format(**locals())
|
||||
],
|
||||
download_url="https://github.com/tpaviot/oce/archive/",
|
||||
download_name="OCE-{OCE_VERSION}.tar.gz".format(**locals())
|
||||
)
|
||||
|
||||
if "libxml2" in targets:
|
||||
build_dependency(
|
||||
"libxml2-{LIBXML_VERSION}".format(**locals()),
|
||||
"autoconf",
|
||||
build_tool_args=[
|
||||
"--without-python",
|
||||
ENABLE_FLAG,
|
||||
DISABLE_FLAG,
|
||||
"--without-zlib",
|
||||
"--without-iconv",
|
||||
"--without-lzma"
|
||||
],
|
||||
download_url="ftp://xmlsoft.org/libxml2/",
|
||||
download_name="libxml2-{LIBXML_VERSION}.tar.gz".format(**locals())
|
||||
)
|
||||
|
||||
if "OpenCOLLADA" in targets:
|
||||
build_dependency(
|
||||
"OpenCOLLADA",
|
||||
"cmake",
|
||||
build_tool_args=[
|
||||
"-DLIBXML2_INCLUDE_DIR={DEPS_DIR}/install/libxml2-{LIBXML_VERSION}/include/libxml2".format(**locals()),
|
||||
"-DLIBXML2_LIBRARIES={DEPS_DIR}/install/libxml2-{LIBXML_VERSION}/lib/libxml2.{LIBRARY_EXT}".format(**locals()),
|
||||
"-DPCRE_INCLUDE_DIR={DEPS_DIR}/install/pcre-{PCRE_VERSION}/include".format(**locals()),
|
||||
"-DPCRE_PCREPOSIX_LIBRARY={DEPS_DIR}/install/pcre-{PCRE_VERSION}/lib/libpcreposix.{LIBRARY_EXT}".format(**locals()),
|
||||
"-DPCRE_PCRE_LIBRARY={DEPS_DIR}/install/pcre-{PCRE_VERSION}/lib/libpcre.{LIBRARY_EXT}".format(**locals()),
|
||||
"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/OpenCOLLADA/".format(**locals())
|
||||
],
|
||||
download_url="https://github.com/KhronosGroup/OpenCOLLADA.git",
|
||||
download_name="OpenCOLLADA",
|
||||
download_tool=download_tool_git,
|
||||
revision=OPENCOLLADA_COMMIT
|
||||
)
|
||||
|
||||
if "python" in targets:
|
||||
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
|
||||
OLD_CXX_FLAGS=os.environ["CXXFLAGS"]
|
||||
OLD_C_FLAGS=os.environ["CFLAGS"]
|
||||
os.environ["CXXFLAGS"]=CXXFLAGS_MINIMAL
|
||||
os.environ["CFLAGS"]=CFLAGS_MINIMAL
|
||||
|
||||
# On OSX a dynamic python library is built or it would not be compatible
|
||||
# with the system python because of some threading initialization
|
||||
PYTHON_CONFIGURE_ARGS=[]
|
||||
if get_os() == "Darwin":
|
||||
PYTHON_CONFIGURE_ARGS=["--disable-static", "--enable-shared"]
|
||||
|
||||
def get_python_unicode_confs(py_ver):
|
||||
if py_ver < "3.3":
|
||||
return [("--enable-unicode=ucs2",""), ("--enable-unicode=ucs4","u")]
|
||||
else: return [("","")]
|
||||
|
||||
def PYTHON_VERSION_CONFS():
|
||||
for v in PYTHON_VERSIONS:
|
||||
for unicode_conf, abi_tag in get_python_unicode_confs(v):
|
||||
yield v, unicode_conf, abi_tag
|
||||
|
||||
for PYTHON_VERSION, unicode_conf, abi_tag in PYTHON_VERSION_CONFS():
|
||||
build_dependency(
|
||||
"python-{PYTHON_VERSION}{abi_tag}".format(**locals()),
|
||||
"autoconf",
|
||||
PYTHON_CONFIGURE_ARGS + [unicode_conf],
|
||||
"http://www.python.org/ftp/python/{PYTHON_VERSION}/".format(**locals()),
|
||||
"Python-{PYTHON_VERSION}.tgz".format(**locals())
|
||||
)
|
||||
|
||||
os.environ["CXXFLAGS"]=OLD_CXX_FLAGS
|
||||
os.environ["CFLAGS"]=OLD_C_FLAGS
|
||||
|
||||
if "boost" in targets:
|
||||
str_concat = lambda prefix: lambda postfix: "" if postfix.strip() == "" else "=".join((prefix, postfix.strip()))
|
||||
build_dependency(
|
||||
"boost-{BOOST_VERSION}".format(**locals()),
|
||||
mode="bjam",
|
||||
build_tool_args=[
|
||||
"--stagedir={DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()),
|
||||
"--with-system",
|
||||
"--with-program_options",
|
||||
"--with-regex",
|
||||
"--with-thread",
|
||||
"--with-date_time",
|
||||
"--with-iostreams",
|
||||
"link={LINK_TYPE}".format(**locals())
|
||||
] + \
|
||||
BOOST_ADDRESS_MODEL + \
|
||||
list(map(str_concat("cxxflags"), CXXFLAGS.strip().split(' '))) + \
|
||||
list(map(str_concat("linkflags"), LDFLAGS.strip().split(' '))) + \
|
||||
["stage", "-s", "NO_BZIP2=1"],
|
||||
download_url="http://downloads.sourceforge.net/project/boost/boost/{BOOST_VERSION}/".format(**locals()),
|
||||
download_name="boost_{BOOST_VERSION_UNDERSCORE}.tar.bz2".format(**locals())
|
||||
)
|
||||
|
||||
cecho("Building IfcOpenShell:", GREEN)
|
||||
|
||||
IFCOS_DIR=os.path.join(DEPS_DIR, "build", "ifcopenshell")
|
||||
if os.path.exists(IFCOS_DIR):
|
||||
shutil.rmtree(IFCOS_DIR)
|
||||
os.makedirs(IFCOS_DIR)
|
||||
|
||||
executables_dir = os.path.join(IFCOS_DIR, "executables")
|
||||
if not os.path.exists(executables_dir):
|
||||
os.makedirs(executables_dir)
|
||||
|
||||
logger.info("\rConfiguring executables...")
|
||||
|
||||
OFF_ON = ["OFF", "ON"]
|
||||
|
||||
cmake_args=[
|
||||
"-DUSE_MMAP=" "OFF",
|
||||
"-DBUILD_EXAMPLES=" "OFF",
|
||||
"-DBUILD_IFCPYTHON=" "OFF",
|
||||
"-DBUILD_SHARED_LIBS=" +OFF_ON[not BUILD_STATIC],
|
||||
"-DBUILD_IFCGEOM=" +OFF_ON["IfcGeom" in targets],
|
||||
"-DBUILD_GEOMSERVER=" +OFF_ON["IfcGeomServer" in targets],
|
||||
"-DBUILD_CONVERT=" +OFF_ON["IfcConvert" in targets],
|
||||
"-DCMAKE_INSTALL_PREFIX=" "{DEPS_DIR}/install/ifcopenshell".format(**locals()),
|
||||
"-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()),
|
||||
"-DGLTF_SUPPORT=" "ON",
|
||||
"-DJSON_INCLUDE_DIR=" "{DEPS_DIR}/install/json".format(**locals())
|
||||
]
|
||||
|
||||
if "occ" in targets and USE_OCCT:
|
||||
occ_include_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/include/opencascade".format(**locals())
|
||||
occ_library_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/lib".format(**locals())
|
||||
cmake_args.extend([
|
||||
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
|
||||
"-DOCC_LIBRARY_DIR=" +occ_library_dir
|
||||
])
|
||||
elif "occ" in targets:
|
||||
occ_include_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/include/oce".format(**locals())
|
||||
occ_library_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/lib"
|
||||
cmake_args.extend([
|
||||
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
|
||||
"-DOCC_LIBRARY_DIR=" +occ_library_dir
|
||||
])
|
||||
|
||||
if "OpenCOLLADA" in targets:
|
||||
cmake_args.extend([
|
||||
"-DOPENCOLLADA_INCLUDE_DIR=" "{DEPS_DIR}/install/OpenCOLLADA/include/opencollada".format(**locals()),
|
||||
"-DOPENCOLLADA_LIBRARY_DIR=" "{DEPS_DIR}/install/OpenCOLLADA/lib/opencollada".format(**locals())
|
||||
])
|
||||
|
||||
if "pcre" in targets:
|
||||
cmake_args.append(
|
||||
"-DPCRE_LIBRARY_DIR=" "{DEPS_DIR}/install/pcre-{PCRE_VERSION}/lib".format(**locals())
|
||||
)
|
||||
|
||||
if "libxml2" in targets:
|
||||
cmake_args.extend([
|
||||
"-DLIBXML2_INCLUDE_DIR=" "{DEPS_DIR}/install/libxml2-{LIBXML_VERSION}/include/libxml2".format(**locals()),
|
||||
"-DLIBXML2_LIBRARIES=" "{DEPS_DIR}/install/libxml2-{LIBXML_VERSION}/lib/libxml2.{LIBRARY_EXT}".format(**locals())
|
||||
])
|
||||
|
||||
run_cmake("", cmake_args, cmake_dir=CMAKE_DIR, cwd=executables_dir)
|
||||
|
||||
logger.info("\rBuilding executables... ")
|
||||
|
||||
run([make, "-j{IFCOS_NUM_BUILD_PROCS}".format(**locals())], cwd=executables_dir)
|
||||
run([make, "install/strip" if BUILD_CFG == "Release" else "install"], cwd=executables_dir)
|
||||
|
||||
if "IfcOpenShell-Python" in targets:
|
||||
|
||||
# On OSX the actual Python library is not linked against.
|
||||
ADDITIONAL_ARGS=""
|
||||
if get_os() == "Darwin":
|
||||
ADDITIONAL_ARGS="-Wl,-flat_namespace,-undefined,suppress"
|
||||
|
||||
os.environ["CXXFLAGS"]="%s %s" % (CXXFLAGS_MINIMAL, ADDITIONAL_ARGS)
|
||||
os.environ["CFLAGS"]="%s %s" % (CFLAGS_MINIMAL, ADDITIONAL_ARGS)
|
||||
os.environ["LDFLAGS"]="%s %s" % (LDFLAGS, ADDITIONAL_ARGS)
|
||||
|
||||
for PYTHON_VERSION, _, TAG in PYTHON_VERSION_CONFS():
|
||||
logger.info("\rConfiguring python {PYTHON_VERSION}{TAG} wrapper...".format(**locals()))
|
||||
|
||||
python_dir = os.path.join(IFCOS_DIR, "python-{PYTHON_VERSION}{TAG}".format(**locals()))
|
||||
if not os.path.exists(python_dir):
|
||||
os.makedirs(python_dir)
|
||||
|
||||
PYTHON_LIBRARY=run([bash, "-c", "ls {DEPS_DIR}/install/python-{PYTHON_VERSION}{TAG}/lib/libpython*.*".format(**locals())])
|
||||
PYTHON_INCLUDE=run([bash, "-c", "ls -d {DEPS_DIR}/install/python-{PYTHON_VERSION}{TAG}/include/python*".format(**locals())])
|
||||
PYTHON_EXECUTABLE=os.path.join(DEPS_DIR, "install", "python-{PYTHON_VERSION}{TAG}".format(**locals()), "bin", "python{PYTHON_VERSION[0]}".format(**locals()))
|
||||
os.environ["PYTHON_LIBRARY_BASENAME"]=os.path.basename(PYTHON_LIBRARY)
|
||||
|
||||
run_cmake("",
|
||||
cmake_args=[
|
||||
"-DBUILD_SHARED_LIBS=" "OFF" if BUILD_STATIC else "ON",
|
||||
"-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()),
|
||||
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
|
||||
"-DOCC_LIBRARY_DIR=" +occ_library_dir,
|
||||
"-DPYTHON_LIBRARY=" +PYTHON_LIBRARY,
|
||||
"-DPYTHON_EXECUTABLE=" +PYTHON_EXECUTABLE,
|
||||
"-DPYTHON_INCLUDE_DIR=" +PYTHON_INCLUDE,
|
||||
"-DSWIG_EXECUTABLE=" "{DEPS_DIR}/install/swig/bin/swig".format(**locals()),
|
||||
"-DCMAKE_INSTALL_PREFIX=" "{DEPS_DIR}/install/ifcopenshell/tmp".format(**locals()),
|
||||
"-DLIBXML2_INCLUDE_DIR=" "{DEPS_DIR}/install/libxml2-{LIBXML_VERSION}/include/libxml2".format(**locals()),
|
||||
"-DLIBXML2_LIBRARIES=" "{DEPS_DIR}/install/libxml2-{LIBXML_VERSION}/lib/libxml2.{LIBRARY_EXT}".format(**locals()),
|
||||
"-DCOLLADA_SUPPORT=OFF"
|
||||
], cmake_dir=CMAKE_DIR, cwd=python_dir)
|
||||
|
||||
logger.info("\rBuilding python %s%s wrapper... " % (PYTHON_VERSION, TAG))
|
||||
|
||||
run([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,), "_ifcopenshell_wrapper"], cwd=python_dir)
|
||||
run([make, "install/local"], cwd=os.path.join(python_dir, "ifcwrap"))
|
||||
|
||||
module_dir = os.path.dirname(run([PYTHON_EXECUTABLE, "-c", "from __future__ import print_function; import inspect, ifcopenshell; print(inspect.getfile(ifcopenshell))"]))
|
||||
|
||||
if get_os() != "Darwin":
|
||||
# TODO: This symbol name depends on the Python version?
|
||||
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
|
||||
|
||||
run([cp, "-R", module_dir, os.path.join(DEPS_DIR, "install", "ifcopenshell", "python-%s%s" % (PYTHON_VERSION, TAG))])
|
||||
|
||||
logger.info("\rBuilt IfcOpenShell...\n\n")
|
||||
@@ -0,0 +1,32 @@
|
||||
http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff;h=0ab4e621833f4eae945a3762c9a29ee12e2eec53#patch1
|
||||
diff --git a/src/HLRBRep/HLRBRep_InternalAlgo.cxx b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
|
||||
index ca885ca..c13cb06 100644 (file)
|
||||
--- a/src/HLRBRep/HLRBRep_InternalAlgo.cxx
|
||||
+++ b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
|
||||
@@ -165,7 +165,7 @@ void HLRBRep_InternalAlgo::Update ()
|
||||
SB.Bounds(v1,v2,e1,e2,f1,f2);
|
||||
|
||||
for (Standard_Integer e = e1; e <= e2; e++) {
|
||||
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
|
||||
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
|
||||
HLRAlgo::DecodeMinMax(ed.MinMax(), TheMin, TheMax);
|
||||
if (FirstTime) {
|
||||
FirstTime = Standard_False;
|
||||
@@ -307,7 +307,7 @@ void HLRBRep_InternalAlgo::InitEdgeStatus ()
|
||||
Standard_Integer nf = myDS->NbFaces();
|
||||
|
||||
for (Standard_Integer e = 1; e <= ne; e++) {
|
||||
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
|
||||
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
|
||||
if (ed.Selected()) ed.Status().ShowAll();
|
||||
}
|
||||
// for (Standard_Integer f = 1; f <= nf; f++) {
|
||||
@@ -368,7 +368,7 @@ void HLRBRep_InternalAlgo::Select ()
|
||||
Standard_Integer nf = myDS->NbFaces();
|
||||
|
||||
for (Standard_Integer e = 1; e <= ne; e++) {
|
||||
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
|
||||
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
|
||||
ed.Selected(Standard_True);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Description: Enable exception handling
|
||||
Upstream defaults to no exception handling for performance reasons,
|
||||
but in OCCT's role as a shared library it's better for Debian to
|
||||
enable it.
|
||||
Author: Kurt Kremitzki <kkremitzki@gmail.com>
|
||||
Last-Update: 2018-06-10
|
||||
|
||||
--- a/adm/cmake/occt_defs_flags.cmake
|
||||
+++ b/adm/cmake/occt_defs_flags.cmake
|
||||
@@ -138,5 +138,5 @@
|
||||
set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
|
||||
endif()
|
||||
|
||||
-set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNo_Exception")
|
||||
-set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNo_Exception")
|
||||
+#set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNo_Exception")
|
||||
+#set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNo_Exception")
|
||||
@@ -1,5 +1,30 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
ADD_EXECUTABLE(IfcParseExamples IfcParseExamples.cpp)
|
||||
TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
|
||||
TARGET_LINK_LIBRARIES(IfcParseExamples IfcParse)
|
||||
set_target_properties(IfcParseExamples PROPERTIES FOLDER Examples)
|
||||
|
||||
ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp)
|
||||
TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset)
|
||||
TARGET_LINK_LIBRARIES(IfcOpenHouse ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES})
|
||||
set_target_properties(IfcOpenHouse PROPERTIES FOLDER Examples)
|
||||
|
||||
ADD_EXECUTABLE(IfcAdvancedHouse IfcAdvancedHouse.cpp)
|
||||
TARGET_LINK_LIBRARIES(IfcAdvancedHouse ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES})
|
||||
set_target_properties(IfcAdvancedHouse PROPERTIES FOLDER Examples)
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_NurbsConvert.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <BRepPrimAPI_MakeSphere.hxx>
|
||||
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#define IfcSchema Ifc4
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/Serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
|
||||
void createGroundShape(TopoDS_Shape& shape);
|
||||
|
||||
int main() {
|
||||
|
||||
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
file.header().file_name().name("IfcAdvancedHouse.ifc");
|
||||
|
||||
IfcSchema::IfcBuilding* building = file.addBuilding();
|
||||
// By adding a building, a hierarchy has been automatically created that consists of the following
|
||||
// structure: IfcProject > IfcSite > IfcBuilding
|
||||
|
||||
// Lateron changing the name of the IfcProject can be done by obtaining a reference to the
|
||||
// project, which has been created automatically.
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("IfcOpenHouse");
|
||||
|
||||
// To demonstrate the ability to serialize arbitrary opencascade solids a building envelope is
|
||||
// constructed by applying boolean operations. Naturally, in IFC, building elements should be
|
||||
// modeled separately, with rich parametric and relational semantics. Creating geometry in this
|
||||
// way does not preserve any history and is merely a demonstration of technical capabilities.
|
||||
TopoDS_Shape outer = BRepPrimAPI_MakeBox(gp_Pnt(-5000., -180., -2000.), gp_Pnt(5000., 5180., 3000.)).Shape();
|
||||
TopoDS_Shape inner = BRepPrimAPI_MakeBox(gp_Pnt(-4640., 180., 0.), gp_Pnt(4640., 4820., 3000.)).Shape();
|
||||
TopoDS_Shape window1 = BRepPrimAPI_MakeBox(gp_Pnt(-5000., -180., 400.), gp_Pnt( 500., 1180., 2000.)).Shape();
|
||||
TopoDS_Shape window2 = BRepPrimAPI_MakeBox(gp_Pnt( 2070., -180., 400.), gp_Pnt(3930., 180., 2000.)).Shape();
|
||||
|
||||
TopoDS_Shape building_shell = BRepAlgoAPI_Cut(
|
||||
BRepAlgoAPI_Cut(
|
||||
BRepAlgoAPI_Cut(outer, inner),
|
||||
window1
|
||||
),
|
||||
window2
|
||||
);
|
||||
|
||||
// Since the solid consists only of planar faces and straight edges it can be serialized as an
|
||||
// IfcFacetedBRep. If it would not be a polyhedron, serialise() can only be successful when linked
|
||||
// to the IFC4 model and with `advanced` set to `true` which introduces IfcAdvancedFace. It would
|
||||
// return `0` otherwise.
|
||||
IfcSchema::IfcProductDefinitionShape* building_shape = IfcGeom::serialise(STRINGIFY(IfcSchema), building_shell, false)->as<IfcSchema::IfcProductDefinitionShape>();
|
||||
|
||||
file.addEntity(building_shape);
|
||||
IfcSchema::IfcRepresentation* rep = *building_shape->Representations()->begin();
|
||||
rep->setContextOfItems(file.getRepresentationContext("model"));
|
||||
|
||||
building->setRepresentation(building_shape);
|
||||
|
||||
// A pale white colour is assigned to the building.
|
||||
file.setSurfaceColour(
|
||||
building_shape, 0.75, 0.73, 0.68);
|
||||
|
||||
// For the ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. Only
|
||||
// in IFC4 the surface can be directly serialized. In IFC2X3 the it will have to be tesselated.
|
||||
TopoDS_Shape shape;
|
||||
createGroundShape(shape);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::serialise(STRINGIFY(IfcSchema), shape, true)->as<IfcSchema::IfcProductDefinitionShape>();
|
||||
if (!ground_representation) {
|
||||
ground_representation = IfcGeom::tesselate(STRINGIFY(IfcSchema), shape, 100.)->as<IfcSchema::IfcProductDefinitionShape>();
|
||||
}
|
||||
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
|
||||
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
|
||||
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
|
||||
}
|
||||
file.addEntity(ground_representation);
|
||||
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
|
||||
|
||||
/*
|
||||
// Note that IFC lacks elementary surfaces that STEP does have, such as spherical_surface.
|
||||
// BRepBuilderAPI_NurbsConvert can be used to serialize such surfaces as nurbs surfaces.
|
||||
TopoDS_Shape sphere = BRepPrimAPI_MakeSphere(gp_Pnt(), 1000.).Shape();
|
||||
IfcSchema::IfcProductDefinitionShape* sphere_representation = IfcGeom::serialise(sphere, true);
|
||||
if (S(IfcSchema::Identifier) == "IFC4") {
|
||||
sphere = BRepBuilderAPI_NurbsConvert(sphere, true).Shape();
|
||||
sphere_representation = IfcGeom::serialise(sphere, true);
|
||||
}
|
||||
*/
|
||||
|
||||
// Finally create a file stream for our output and write the IFC file to it.
|
||||
std::ofstream f("IfcAdvancedHouse.ifc");
|
||||
f << file;
|
||||
}
|
||||
|
||||
void createGroundShape(TopoDS_Shape& shape) {
|
||||
TColgp_Array2OfPnt cv (0, 4, 0, 4);
|
||||
cv.SetValue(0, 0, gp_Pnt(-10000, -10000, -4130));
|
||||
cv.SetValue(0, 1, gp_Pnt(-10000, -4330, -4130));
|
||||
cv.SetValue(0, 2, gp_Pnt(-10000, 0, -5130));
|
||||
cv.SetValue(0, 3, gp_Pnt(-10000, 4330, -7130));
|
||||
cv.SetValue(0, 4, gp_Pnt(-10000, 10000, -7130));
|
||||
cv.SetValue(1, 0, gp_Pnt( -3330, -10000, -5130));
|
||||
cv.SetValue(1, 1, gp_Pnt( -7670, -3670, 5000));
|
||||
cv.SetValue(1, 2, gp_Pnt( -9000, 0, 1000));
|
||||
cv.SetValue(1, 3, gp_Pnt( -7670, 7670, 6000));
|
||||
cv.SetValue(1, 4, gp_Pnt( -3330, 10000, -4130));
|
||||
cv.SetValue(2, 0, gp_Pnt( 0, -10000, -5530));
|
||||
cv.SetValue(2, 1, gp_Pnt( 0, -3670, 3000));
|
||||
cv.SetValue(2, 2, gp_Pnt( 0, 0, -12000));
|
||||
cv.SetValue(2, 3, gp_Pnt( 0, 7670, 1500));
|
||||
cv.SetValue(2, 4, gp_Pnt( 0, 10000, -4130));
|
||||
cv.SetValue(3, 0, gp_Pnt( 3330, -10000, -6130));
|
||||
cv.SetValue(3, 1, gp_Pnt( 7670, -3670, 6000));
|
||||
cv.SetValue(3, 2, gp_Pnt( 9000, 0, 5000));
|
||||
cv.SetValue(3, 3, gp_Pnt( 7670, 9000, 7000));
|
||||
cv.SetValue(3, 4, gp_Pnt( 3330, 10000, -4130));
|
||||
cv.SetValue(4, 0, gp_Pnt( 10000, -10000, -6130));
|
||||
cv.SetValue(4, 1, gp_Pnt( 10000, -4330, -5130));
|
||||
cv.SetValue(4, 2, gp_Pnt( 10000, 0, -4130));
|
||||
cv.SetValue(4, 3, gp_Pnt( 10000, 4330, -4130));
|
||||
cv.SetValue(4, 4, gp_Pnt( 10000, 10000, -8130));
|
||||
TColStd_Array1OfReal knots(0, 1);
|
||||
knots(0) = 0;
|
||||
knots(1) = 1;
|
||||
TColStd_Array1OfInteger mult(0, 1);
|
||||
mult(0) = 5;
|
||||
mult(1) = 5;
|
||||
Handle(Geom_BSplineSurface) surf = new Geom_BSplineSurface(cv, knots, knots, mult, mult, 4, 4);
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
shape = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
shape = BRepBuilderAPI_MakeFace(surf, Precision::Confusion());
|
||||
#endif
|
||||
}
|
||||
@@ -28,33 +28,42 @@
|
||||
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#include <BRepGProp.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#define IfcSchema Ifc4
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/Serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
// Some convenience typedefs and definitions.
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
typedef std::pair<double, double> XY;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
|
||||
void createGroundShape(TopoDS_Shape& shape);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main() {
|
||||
|
||||
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
IfcHierarchyHelper file;
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
file.header().file_name().name("IfcOpenHouse.ifc");
|
||||
|
||||
// Start by adding a wall to the file, initially leaving most attributes blank.
|
||||
@@ -195,45 +204,48 @@ int main(int argc, char** argv) {
|
||||
file.addBuildingProduct(north_wall);
|
||||
file.setSurfaceColour(north_wall->Representation(), wall_colour);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* clipped_wall_body_rep = file.addEmptyRepresentation();
|
||||
file.addBox(clipped_wall_body_rep, 5000, 360, 6000);
|
||||
// The east wall geometry is clipped using two IfcHalfSpaceSolids, created from an
|
||||
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
|
||||
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
|
||||
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
|
||||
// Two identical representations are created for the two remaining walls. Mapped items
|
||||
// are not used, because it is not allowed by the standard for wall body representations.
|
||||
// MappedItems are not allowed for Axis representations as per CV-2x3-161
|
||||
IfcSchema::IfcProductDefinitionShape* clipped_wall_body_reps[2];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
IfcSchema::IfcShapeRepresentation* body = file.addEmptyRepresentation();
|
||||
file.addBox(body, 5000, 360, 6000);
|
||||
// The wall geometry is clipped using two IfcHalfSpaceSolids, created from an
|
||||
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
|
||||
file.clipRepresentation(body, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
|
||||
file.clipRepresentation(body, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
|
||||
file.setSurfaceColour(body, wall_colour);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* axis = file.addEmptyRepresentation("Axis", "Curve2D");
|
||||
file.addAxis(axis, 5000);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
reps->push(body);
|
||||
reps->push(axis);
|
||||
clipped_wall_body_reps[i] = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
}
|
||||
|
||||
// Now create a wall on the east of the building, again starting with just a box shape
|
||||
IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addMappedItem(clipped_wall_body_rep), null
|
||||
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), clipped_wall_body_reps[0], null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(east_wall);
|
||||
|
||||
file.setSurfaceColour(clipped_wall_body_rep, wall_colour);
|
||||
|
||||
// The east wall is copied to the west location of the house
|
||||
IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), file.addMappedItem(clipped_wall_body_rep), null
|
||||
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), clipped_wall_body_reps[1], null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(west_wall);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
// CV-2x3-161: MappedItems are not allowed for Axis representations
|
||||
IfcSchema::IfcWallStandardCase* wall = i == 0 ? east_wall : west_wall;
|
||||
IfcSchema::IfcShapeRepresentation* wall_axis_rep = file.addEmptyRepresentation("Axis", "Curve2D");
|
||||
file.addAxis(wall_axis_rep, 5000);
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = wall->Representation()->Representations();
|
||||
reps->push(wall_axis_rep);
|
||||
wall->Representation()->setRepresentations(reps);
|
||||
}
|
||||
|
||||
// The west wall is assigned an opening element we created for the south wall, opening elements are
|
||||
// not shared accross building elements, even if they share the same representation. Hence, the east
|
||||
// not shared across building elements, even if they share the same representation. Hence, the east
|
||||
// wall will not feature this opening.
|
||||
// NB: an Opening Element can only be used to create a single void within a single Element, as per:
|
||||
// http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcproductextension/lexical/ifcfeatureelementsubtraction.htm
|
||||
@@ -255,14 +267,30 @@ int main(int argc, char** argv) {
|
||||
// will be tesselated using the deflection specified.
|
||||
TopoDS_Shape shape;
|
||||
createGroundShape(shape);
|
||||
IfcEntityList::ptr geometrical_entities(new IfcEntityList);
|
||||
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
|
||||
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(STRINGIFY(IfcSchema), shape, 100.)->as<IfcSchema::IfcProductDefinitionShape>();
|
||||
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
|
||||
file.addEntities(geometrical_entities);
|
||||
IfcSchema::IfcShapeRepresentation::list::ptr ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
|
||||
for (IfcSchema::IfcShapeRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
|
||||
|
||||
GProp_GProps prop;
|
||||
BRepGProp::SurfaceProperties(shape, prop);
|
||||
const double site_area = prop.Mass() / 1000 / 1000;
|
||||
|
||||
IfcSchema::IfcProperty::list::ptr properties(new IfcSchema::IfcProperty::list);
|
||||
properties->push(new IfcSchema::IfcPropertySingleValue("TotalArea", null, new IfcSchema::IfcAreaMeasure(site_area), 0));
|
||||
IfcSchema::IfcPropertySet* pset = new IfcSchema::IfcPropertySet(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Pset_SiteCommon"), null, properties);
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcObjectDefinition::list::ptr related_objs(new IfcSchema::IfcObjectDefinition::list);
|
||||
#else
|
||||
IfcSchema::IfcObject::list::ptr related_objs(new IfcSchema::IfcObject::list);
|
||||
#endif
|
||||
related_objs->push(file.getSingle<IfcSchema::IfcSite>());
|
||||
IfcSchema::IfcRelDefinesByProperties* site_prop = new IfcSchema::IfcRelDefinesByProperties(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, related_objs, pset);
|
||||
file.addEntity(site_prop);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
|
||||
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
|
||||
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
|
||||
}
|
||||
file.addEntity(ground_representation);
|
||||
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
|
||||
|
||||
// According to the Ifc2x3 schema an IfcWallStandardCase needs to have an IfcMaterialLayerSet
|
||||
@@ -313,9 +341,9 @@ int main(int argc, char** argv) {
|
||||
null,
|
||||
null,
|
||||
#ifdef USE_IFC4
|
||||
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->generalize(),
|
||||
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->generalize(),
|
||||
#else
|
||||
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
|
||||
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
|
||||
#endif
|
||||
layer_usage);
|
||||
|
||||
@@ -370,7 +398,7 @@ int main(int argc, char** argv) {
|
||||
IfcSchema::IfcShapeRepresentation* door_body = 0;
|
||||
for (IfcSchema::IfcRepresentation::list::it i = door_representations->begin(); i != door_representations->end(); ++i) {
|
||||
IfcSchema::IfcRepresentation* rep = *i;
|
||||
if (rep->is(IfcSchema::Type::IfcShapeRepresentation) && rep->RepresentationIdentifier() == "Body") {
|
||||
if (rep->declaration().is(IfcSchema::IfcShapeRepresentation::Class()) && rep->RepresentationIdentifier() == "Body") {
|
||||
door_body = (IfcSchema::IfcShapeRepresentation*) rep;
|
||||
}
|
||||
}
|
||||
@@ -381,13 +409,17 @@ int main(int argc, char** argv) {
|
||||
file.setSurfaceColour(door->Representation(), 0.9, 0.9, 0.9);
|
||||
file.addEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, door_opening, door));
|
||||
|
||||
IfcSchema::IfcDoorStyle* door_style = new IfcSchema::IfcDoorStyle(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Door type"), null, null, null, null, null,
|
||||
IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT, IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD, false, false);
|
||||
file.addRelatedObject<IfcSchema::IfcRelDefinesByType>(door_style, door);
|
||||
|
||||
// Surface styles are assigned to representation items, hence there is no real limitation to
|
||||
// assign different colours within the same representation. However, some viewers have
|
||||
// difficulties rendering products with representation items with different surface styles.
|
||||
// Therefore we will construct the window as a decomposition of beams and a plate, in which
|
||||
// only the plate will have a transparent material assigned.
|
||||
|
||||
// The window frame will consists of four seperate beams.
|
||||
// The window frame will consists of four separate beams.
|
||||
// AutoCAD Architecture will create an internal window type for the IfcWindow created.
|
||||
// Therefore the OverallWidth and OverallHeight of the window attributes will need to
|
||||
// match the bounding box of the representation. Furthermore, the window placement needs
|
||||
@@ -438,10 +470,10 @@ int main(int argc, char** argv) {
|
||||
);
|
||||
file.addBuildingProduct(window);
|
||||
|
||||
// Initalize a list of parts for the window to be composed of
|
||||
// Initialize a list of parts for the window to be composed of
|
||||
IfcSchema::IfcObjectDefinition::list::ptr window_parts(new IfcTemplatedEntityList<IfcSchema::IfcObjectDefinition>());
|
||||
|
||||
// The placements for the beams are not shared accross the different windows because every
|
||||
// The placements for the beams are not shared across the different windows because every
|
||||
// beam is placed relative to its parent window entity.
|
||||
IfcSchema::IfcLocalPlacement::list::ptr frame_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 930,45));
|
||||
|
||||
@@ -17,9 +17,15 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
// TODO: Multiple schemas
|
||||
#define IfcSchema Ifc2x3
|
||||
|
||||
using namespace IfcSchema;
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -32,8 +38,8 @@ int main(int argc, char** argv) {
|
||||
Logger::SetOutput(&std::cout,&std::cout);
|
||||
|
||||
// Parse the IFC file provided in argv[1]
|
||||
IfcParse::IfcFile file;
|
||||
if ( ! file.Init(argv[1]) ) {
|
||||
IfcParse::IfcFile file(argv[1]);
|
||||
if (!file.good()) {
|
||||
std::cout << "Unable to parse .ifc file" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
@@ -54,19 +60,18 @@ int main(int argc, char** argv) {
|
||||
// we need to cast them to IfcWindows. Since these properties
|
||||
// are optional we need to make sure the properties are
|
||||
// defined for the window in question before accessing them.
|
||||
IfcBuildingElement::list::ptr elements = file.entitiesByType<IfcBuildingElement>();
|
||||
IfcSchema::IfcBuildingElement::list::ptr elements = file.instances_by_type<IfcSchema::IfcBuildingElement>();
|
||||
|
||||
std::cout << "Found " << elements->size() << " elements in " << argv[1] << ":" << std::endl;
|
||||
|
||||
for ( IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++ it ) {
|
||||
for (IfcSchema::IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++it) {
|
||||
|
||||
const IfcBuildingElement* element = *it;
|
||||
std::cout << element->entity->toString() << std::endl;
|
||||
const IfcSchema::IfcBuildingElement* element = *it;
|
||||
std::cout << element->data().toString() << std::endl;
|
||||
|
||||
if ( element->is(IfcWindow::Class()) ) {
|
||||
const IfcWindow* window = (IfcWindow*)element;
|
||||
|
||||
if ( window->hasOverallWidth() && window->hasOverallHeight() ) {
|
||||
const IfcSchema::IfcWindow* window;
|
||||
if ((window = element->as<IfcSchema::IfcWindow>()) != 0) {
|
||||
if (window->hasOverallWidth() && window->hasOverallHeight()) {
|
||||
const double area = window->OverallWidth()*window->OverallHeight();
|
||||
std::cout << "The area of this window is " << area << std::endl;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
static int i = 0;
|
||||
|
||||
void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
|
||||
@@ -43,16 +43,16 @@ void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresenta
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(120 * i++));
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 120 * i++));
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(item);
|
||||
|
||||
if (s == "GeometricSet") {
|
||||
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
|
||||
file.addEntity(set);
|
||||
items = IfcSchema::IfcRepresentationItem::list(new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(set);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresenta
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), s, items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
@@ -109,11 +109,11 @@ void create_products_from_curve(IfcHierarchyHelper& file, IfcSchema::IfcBoundedC
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcArbitraryOpenProfileDef.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {-50.0, 0.0};
|
||||
double coords2[] = { 50.0, 0.0};
|
||||
IfcSchema::IfcCartesianPoint::list points (new IfcTemplatedEntityList<IfcSchema::IfcCartesianPoint>());
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list());
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords1, coords1+2)));
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords2, coords2+2)));
|
||||
file.addEntities(points->generalize());
|
||||
@@ -126,8 +126,8 @@ int main(int argc, char** argv) {
|
||||
file.addEntity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
trim1->push(new IfcWrite::IfcSelectHelper( 0., Ifc2x3::Type::IfcParameterValue));
|
||||
trim2->push(new IfcWrite::IfcSelectHelper(180., Ifc2x3::Type::IfcParameterValue));
|
||||
trim1->push(new IfcSchema::IfcParameterValue( 0.));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(180.));
|
||||
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.addEntity(trim);
|
||||
|
||||
|
||||
@@ -32,19 +32,19 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCompositeProfileDef.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {100.0, 0.0};
|
||||
double coords2[] = {200.0, 0.0};
|
||||
double coords3[] = {300.0, 0.0};
|
||||
|
||||
IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list());
|
||||
|
||||
IfcSchema::IfcCartesianTransformationOperator2D* transform1 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), null);
|
||||
IfcSchema::IfcCartesianTransformationOperator2D* transform2 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), 0.3);
|
||||
@@ -98,15 +98,15 @@ int main(int argc, char** argv) {
|
||||
file.addEntity(composite);
|
||||
file.addEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
class Node {
|
||||
private:
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCsgPrimitive.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
IfcSchema::IfcRepresentationItem* csg1 = Node::Box(8000.,6000.,3000.).subtract(
|
||||
Node::Box(7600.,5600.,2800.).move(200.,200.,200.)
|
||||
@@ -171,8 +171,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(csg1);
|
||||
items->push(csg2);
|
||||
@@ -180,7 +180,7 @@ int main(int argc, char** argv) {
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("CSG"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
typedef struct {
|
||||
double r1;
|
||||
@@ -58,7 +58,7 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
|
||||
Ifc2x3::IfcCartesianPoint* p2 = new Ifc2x3::IfcCartesianPoint(coords2);
|
||||
Ifc2x3::IfcCartesianPoint* p3 = new Ifc2x3::IfcCartesianPoint(coords3);
|
||||
|
||||
Ifc2x3::IfcCartesianPoint::list points(new IfcTemplatedEntityList<Ifc2x3::IfcCartesianPoint>());
|
||||
Ifc2x3::IfcCartesianPoint::list::ptr points(new Ifc2x3::IfcCartesianPoint::list());
|
||||
points->push(p3);
|
||||
points->push(p1);
|
||||
points->push(p2);
|
||||
@@ -70,8 +70,8 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
if (pref == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER) {
|
||||
trim1->push(new IfcWrite::IfcSelectHelper(pie.t1, Ifc2x3::Type::IfcParameterValue));
|
||||
trim2->push(new IfcWrite::IfcSelectHelper(pie.t2, Ifc2x3::Type::IfcParameterValue));
|
||||
trim1->push(new Ifc2x3::IfcParameterValue(pie.t1));
|
||||
trim2->push(new Ifc2x3::IfcParameterValue(pie.t2));
|
||||
} else {
|
||||
trim1->push(p2);
|
||||
trim2->push(p3);
|
||||
@@ -79,7 +79,7 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
|
||||
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1, trim2, true, pref);
|
||||
file.addEntity(trim);
|
||||
|
||||
Ifc2x3::IfcCompositeCurveSegment::list segments(new IfcTemplatedEntityList<Ifc2x3::IfcCompositeCurveSegment>());
|
||||
Ifc2x3::IfcCompositeCurveSegment::list::ptr segments(new Ifc2x3::IfcCompositeCurveSegment::list());
|
||||
Ifc2x3::IfcCompositeCurveSegment* s2 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
|
||||
|
||||
Ifc2x3::IfcPolyline* poly = new Ifc2x3::IfcPolyline(points);
|
||||
@@ -100,22 +100,22 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(200 * i++));
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 200 * i++));
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates various forms of IfcFace *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
static int x = 0;
|
||||
|
||||
void create_testcase(IfcHierarchyHelper& file, IfcSchema::IfcFace* face, const std::string& name) {
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
faces->push(face);
|
||||
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
||||
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
|
||||
shells->push(shell);
|
||||
IfcSchema::IfcFaceBasedSurfaceModel* model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, name, null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 1000 * x++, 0));
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
items->push(model);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
IfcHierarchyHelper file;
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "polyloop");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
|
||||
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
|
||||
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
|
||||
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
|
||||
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
|
||||
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
edges->push(oriented_edge1);
|
||||
edges->push(oriented_edge2);
|
||||
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "circle");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* outer_bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, -300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, +300, 0));
|
||||
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
|
||||
IfcSchema::IfcFaceBound* inner_bound1 = new IfcSchema::IfcFaceBound(loop2, false);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points3 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, +300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, -300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -300, 0));
|
||||
IfcSchema::IfcPolyLoop* loop3 = new IfcSchema::IfcPolyLoop(points3);
|
||||
IfcSchema::IfcFaceBound* inner_bound2 = new IfcSchema::IfcFaceBound(loop3, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(inner_bound1);
|
||||
bounds->push(outer_bound);
|
||||
bounds->push(inner_bound2);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "polyloop with holes");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound1 = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
|
||||
IfcSchema::IfcFaceOuterBound* bound2 = new IfcSchema::IfcFaceOuterBound(loop2, false);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound1);
|
||||
bounds->push(bound2);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "multiple outer boundaries (invalid)");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 1e-6));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "imprecise polyloop");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
|
||||
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
|
||||
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
|
||||
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
|
||||
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
|
||||
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
edges->push(oriented_edge1);
|
||||
edges->push(oriented_edge2);
|
||||
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr trim1(new IfcSchema::IfcCartesianPoint::list);
|
||||
IfcSchema::IfcCartesianPoint::list::ptr trim2(new IfcSchema::IfcCartesianPoint::list);
|
||||
trim1->push(point1);
|
||||
trim2->push(point2);
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1->generalize(), trim2->generalize(), true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);
|
||||
IfcSchema::IfcArbitraryOpenProfileDef* profile = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, boost::none, trimmed_curve);
|
||||
IfcSchema::IfcAxis1Placement* place = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0., 0., 0.), file.addTriplet<IfcSchema::IfcDirection>(1., 0., 0.));
|
||||
IfcSchema::IfcSurfaceOfRevolution* surface = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), place);
|
||||
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFaceSurface(bounds, surface, true);
|
||||
create_testcase(file, face, "face surface");
|
||||
}
|
||||
const std::string filename = "faces.ifc";
|
||||
file.header().file_name().name(filename);
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example of curve rebar. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include "ifcparse\Ifc2x3.h"
|
||||
#include "ifcparse\IfcUtil.h"
|
||||
#include "ifcparse\IfcHierarchyHelper.h"
|
||||
#include "ifcgeom\IfcGeom.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
void create_curve_rebar(IfcHierarchyHelper& file)
|
||||
{
|
||||
int dia = 24;
|
||||
int R = 3 * dia;
|
||||
int length = 12 * dia;
|
||||
|
||||
double crossSectionarea = M_PI * (dia / 2) * 2;
|
||||
IfcSchema::IfcReinforcingBar* rebar = new IfcSchema::IfcReinforcingBar(
|
||||
guid(), 0, S("test"), null,
|
||||
null, 0, 0,
|
||||
null, S("SR24"), //SteelGrade
|
||||
dia, //diameter
|
||||
crossSectionarea, //crossSectionarea = math.pi*(12.0/2)**2
|
||||
0,
|
||||
IfcSchema::IfcReinforcingBarRoleEnum::IfcReinforcingBarRoleEnum::IfcReinforcingBarRole_LIGATURE,
|
||||
IfcSchema::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurface_PLAIN //PLAIN or TEXTURED
|
||||
);
|
||||
|
||||
file.addBuildingProduct(rebar);
|
||||
rebar->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments(new IfcSchema::IfcCompositeCurveSegment::list());
|
||||
|
||||
IfcSchema::IfcCartesianPoint* p1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 1000.);
|
||||
IfcSchema::IfcCartesianPoint* p2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 0);
|
||||
IfcSchema::IfcCartesianPoint* p3 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, 0);
|
||||
IfcSchema::IfcCartesianPoint* p4 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, -R);
|
||||
IfcSchema::IfcCartesianPoint* p5 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R + length, -R);
|
||||
|
||||
/*first segment - line */
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points1(new IfcSchema::IfcCartesianPoint::list());
|
||||
points1->push(p1);
|
||||
points1->push(p2);
|
||||
file.addEntities(points1->generalize());
|
||||
IfcSchema::IfcPolyline* poly1 = new IfcSchema::IfcPolyline(points1);
|
||||
file.addEntity(poly1);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment1 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly1);
|
||||
file.addEntity(segment1);
|
||||
segments->push(segment1);
|
||||
|
||||
/*second segment - arc */
|
||||
IfcSchema::IfcAxis2Placement3D* axis1 = new IfcSchema::IfcAxis2Placement3D(p3, file.addTriplet<IfcSchema::IfcDirection>(1, 0, 0), file.addTriplet<IfcSchema::IfcDirection>(0, 1, 0));
|
||||
file.addEntity(axis1);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(axis1, R);
|
||||
file.addEntity(circle);
|
||||
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
|
||||
trim1->push(new IfcSchema::IfcParameterValue(180));
|
||||
trim1->push(p2);
|
||||
|
||||
trim2->push(new IfcSchema::IfcParameterValue(270));
|
||||
trim2->push(p4);
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1, trim2, false, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.addEntity(trimmed_curve);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment2 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, false, trimmed_curve);
|
||||
file.addEntity(segment2);
|
||||
segments->push(segment2);
|
||||
|
||||
/*third segment - line */
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2(new IfcSchema::IfcCartesianPoint::list());
|
||||
points2->push(p4);
|
||||
points2->push(p5);
|
||||
file.addEntities(points2->generalize());
|
||||
IfcSchema::IfcPolyline* poly2 = new IfcSchema::IfcPolyline(points2);
|
||||
file.addEntity(poly2);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment3 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly2);
|
||||
file.addEntity(segment3);
|
||||
segments->push(segment3);
|
||||
|
||||
IfcSchema::IfcCompositeCurve* curve = new IfcSchema::IfcCompositeCurve(segments, false);
|
||||
file.addEntity(curve);
|
||||
|
||||
IfcSchema::IfcSweptDiskSolid* solid = new IfcSchema::IfcSweptDiskSolid(curve, dia / 2, null, 0, 1);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("AdvancedSweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.addEntity(shape);
|
||||
|
||||
rebar->setRepresentation(shape);
|
||||
|
||||
IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
|
||||
rebar->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 0, 0));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
IfcHierarchyHelper file;
|
||||
file.header().file_name().name("ifc_curve_rebar.ifc");
|
||||
create_curve_rebar(file);
|
||||
std::ofstream f("ifc_curve_rebar.ifc");
|
||||
f << file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates an IfcTriangulatedFaceSet *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
#include "suzanne_geometry.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
template <typename T>
|
||||
std::vector< std::vector<T> > create_vector_from_array(const T* arr, unsigned size) {
|
||||
std::vector< std::vector<T> > result;
|
||||
result.reserve(size);
|
||||
|
||||
for (unsigned i = 0; i < size; ) {
|
||||
std::vector<T> ts; ts.reserve(3);
|
||||
for (unsigned j = 0; j < 3; ++i, ++j) {
|
||||
ts.push_back(arr[i]);
|
||||
}
|
||||
result.push_back(ts);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
IfcHierarchyHelper file;
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("Blender's Suzanne"), null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
std::vector< std::vector< double > > vertices_vector = create_vector_from_array(vertices, sizeof(vertices) / sizeof(vertices[0]));
|
||||
std::vector< std::vector< int > > indices_vector = create_vector_from_array(indices, sizeof(indices) / sizeof(indices[0]));
|
||||
|
||||
IfcSchema::IfcCartesianPointList3D* coordinates = new IfcSchema::IfcCartesianPointList3D(vertices_vector);
|
||||
IfcSchema::IfcTriangulatedFaceSet* faceset = new IfcSchema::IfcTriangulatedFaceSet(coordinates, null, null, indices_vector, null);
|
||||
|
||||
items->push(faceset);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
const std::string filename = "tesselated_faceset.ifc";
|
||||
file.header().file_name().name(filename);
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
@@ -27,46 +27,51 @@
|
||||
|
||||
bl_info = {
|
||||
"name": "IfcBlender",
|
||||
"description": "Import files in the "\
|
||||
"description": "Import files in the "
|
||||
"Industry Foundation Classes (.ifc) file format",
|
||||
"author": "Thomas Krijnen, IfcOpenShell",
|
||||
"blender": (2, 73, 0),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "File > Import",
|
||||
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"\
|
||||
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"
|
||||
"_list/tickets?source=navbar",
|
||||
"category": "Import-Export"}
|
||||
|
||||
if "bpy" in locals():
|
||||
import imp
|
||||
import importlib
|
||||
if "ifcopenshell" in locals():
|
||||
imp.reload(ifcopenshell)
|
||||
importlib.reload(ifcopenshell)
|
||||
|
||||
import bpy
|
||||
import mathutils
|
||||
from bpy.props import StringProperty, IntProperty, BoolProperty
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
|
||||
major,minor = bpy.app.version[0:2]
|
||||
major, minor = bpy.app.version[0:2]
|
||||
transpose_matrices = minor >= 62
|
||||
|
||||
bpy.types.Object.ifc_id = IntProperty(name="IFC Entity ID",
|
||||
bpy.types.Object.ifc_id = IntProperty(
|
||||
name="IFC Entity ID",
|
||||
description="The STEP entity instance name")
|
||||
bpy.types.Object.ifc_guid = StringProperty(name="IFC Entity GUID",
|
||||
bpy.types.Object.ifc_guid = StringProperty(
|
||||
name="IFC Entity GUID",
|
||||
description="The IFC Globally Unique Identifier")
|
||||
bpy.types.Object.ifc_name = StringProperty(name="IFC Entity Name",
|
||||
bpy.types.Object.ifc_name = StringProperty(
|
||||
name="IFC Entity Name",
|
||||
description="The optional name attribute")
|
||||
bpy.types.Object.ifc_type = StringProperty(name="IFC Entity Type",
|
||||
bpy.types.Object.ifc_type = StringProperty(
|
||||
name="IFC Entity Type",
|
||||
description="The STEP Datatype keyword")
|
||||
|
||||
|
||||
def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
from . import ifcopenshell
|
||||
from .ifcopenshell import geom as ifcopenshell_geom
|
||||
print("Reading %s..."%bpy.path.basename(filename))
|
||||
print(f"Reading {bpy.path.basename(filename)}...")
|
||||
settings = ifcopenshell_geom.settings()
|
||||
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
|
||||
iterator = ifcopenshell_geom.iterator(settings, filename)
|
||||
valid_file = iterator.findContext()
|
||||
file = ifcopenshell.open(filename)
|
||||
iterator = ifcopenshell_geom.iterator(settings, file)
|
||||
valid_file = iterator.initialize()
|
||||
if not valid_file:
|
||||
return False
|
||||
print("Done reading file")
|
||||
@@ -76,9 +81,14 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
openings = []
|
||||
old_progress = -1
|
||||
print("Creating geometry...")
|
||||
collection = bpy.data.collections.new(f"{bpy.path.basename(filename)}")
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
if process_relations:
|
||||
rel_collection = bpy.data.collections.new("Relations")
|
||||
collection.children.link(rel_collection)
|
||||
while True:
|
||||
ob = iterator.get()
|
||||
|
||||
|
||||
f = ob.geometry.faces
|
||||
v = ob.geometry.verts
|
||||
mats = ob.geometry.materials
|
||||
@@ -86,52 +96,77 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
m = ob.transformation.matrix.data
|
||||
t = ob.type[0:21]
|
||||
nm = ob.name if len(ob.name) and use_names else ob.guid
|
||||
# MESH CREATION
|
||||
# Depending on version, geometry.id will be either int or str
|
||||
mesh_name = 'mesh-%r' % ob.geometry.id
|
||||
if mesh_name in bpy.data.meshes:
|
||||
me = bpy.data.meshes[mesh_name]
|
||||
else:
|
||||
verts = [[v[i], v[i + 1], v[i + 2]]
|
||||
for i in range(0, len(v), 3)]
|
||||
faces = [[f[i], f[i + 1], f[i + 2]]
|
||||
for i in range(0, len(f), 3)]
|
||||
|
||||
verts = [[v[i], v[i + 1], v[i + 2]] \
|
||||
for i in range(0, len(v), 3)]
|
||||
faces = [[f[i], f[i + 1], f[i + 2]] \
|
||||
for i in range(0, len(f), 3)]
|
||||
me = bpy.data.meshes.new(mesh_name)
|
||||
me.from_pydata(verts, [], faces)
|
||||
me.validate()
|
||||
# MATERIAL CREATION
|
||||
def add_material(mname, props):
|
||||
if mname in bpy.data.materials:
|
||||
mat = bpy.data.materials[mname]
|
||||
mat.use_fake_user = True
|
||||
else:
|
||||
mat = bpy.data.materials.new(mname)
|
||||
for k, v in props.items():
|
||||
if k == 'transparency':
|
||||
mat.blend_method = 'HASHED'
|
||||
mat.use_screen_refraction = True
|
||||
mat.refraction_depth = 0.1
|
||||
mat.use_nodes = True
|
||||
mat.node_tree.nodes["Principled BSDF"].inputs[15].default_value = v
|
||||
else:
|
||||
setattr(mat, k, v)
|
||||
me.materials.append(mat)
|
||||
|
||||
me = bpy.data.meshes.new('mesh%d' % ob.geometry.id)
|
||||
me.from_pydata(verts, [], faces)
|
||||
|
||||
def add_material(mname, props):
|
||||
if mname in bpy.data.materials:
|
||||
mat = bpy.data.materials[mname]
|
||||
mat.use_fake_user = True
|
||||
else:
|
||||
mat = bpy.data.materials.new(mname)
|
||||
for k,v in props.items():
|
||||
setattr(mat, k, v)
|
||||
me.materials.append(mat)
|
||||
|
||||
needs_default = -1 in matids
|
||||
if needs_default: add_material(t, {})
|
||||
|
||||
for mat in mats:
|
||||
props = {}
|
||||
if mat.has_diffuse: props['diffuse_color'] = mat.diffuse
|
||||
if mat.has_specular: props['specular_color'] = mat.specular
|
||||
if mat.has_transparency and mat.transparency > 0:
|
||||
props['alpha'] = 1.0 - mat.transparency
|
||||
props['use_transparency'] = True
|
||||
if mat.has_specularity: props['specular_hardness'] = mat.specularity
|
||||
add_material(mat.name, props)
|
||||
needs_default = -1 in matids
|
||||
if needs_default:
|
||||
add_material(t, {})
|
||||
|
||||
for mat in mats:
|
||||
props = {}
|
||||
if mat.has_diffuse:
|
||||
alpha = 1.
|
||||
if mat.has_transparency and mat.transparency > 0:
|
||||
alpha = 1. - mat.transparency
|
||||
props['diffuse_color'] = mat.diffuse + (alpha,)
|
||||
# @todo
|
||||
# if mat.has_specular:
|
||||
# props['specular_color'] = mat.specular
|
||||
# if mat.has_specularity:
|
||||
# props['specular_intensity'] = mat.specularity
|
||||
add_material(mat.name, props)
|
||||
|
||||
faces = me.polygons if hasattr(me, 'polygons') else me.faces
|
||||
if len(faces) == len(matids):
|
||||
for face, matid in zip(faces, matids):
|
||||
face.material_index = matid + (1 if needs_default else 0)
|
||||
|
||||
# OBJECT CREATION
|
||||
bob = bpy.data.objects.new(nm, me)
|
||||
mat = mathutils.Matrix(([m[0], m[1], m[2], 0],
|
||||
[m[3], m[4], m[5], 0],
|
||||
[m[6], m[7], m[8], 0],
|
||||
[m[9], m[10], m[11], 1]))
|
||||
if transpose_matrices: mat.transpose()
|
||||
|
||||
[m[3], m[4], m[5], 0],
|
||||
[m[6], m[7], m[8], 0],
|
||||
[m[9], m[10], m[11], 1]))
|
||||
if transpose_matrices:
|
||||
mat.transpose()
|
||||
|
||||
if process_relations:
|
||||
id_to_matrix[ob.id] = mat
|
||||
else:
|
||||
bob.matrix_world = mat
|
||||
bpy.context.scene.objects.link(bob)
|
||||
collection.objects.link(bob)
|
||||
|
||||
bpy.context.scene.objects.active = bob
|
||||
bpy.context.view_layer.objects.active = bob
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.normals_make_consistent()
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
@@ -141,23 +176,19 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
|
||||
if ob.type == 'IfcSpace' or ob.type == 'IfcOpeningElement':
|
||||
if not (ob.type == 'IfcOpeningElement' and blender_booleans):
|
||||
bob.hide = bob.hide_render = True
|
||||
bob.draw_type = 'WIRE'
|
||||
|
||||
if ob.id not in id_to_object: id_to_object[ob.id] = []
|
||||
bob.hide_viewport = bob.hide_render = True
|
||||
bob.display_type = 'WIRE'
|
||||
|
||||
if ob.id not in id_to_object:
|
||||
id_to_object[ob.id] = []
|
||||
id_to_object[ob.id].append(bob)
|
||||
|
||||
if ob.parent_id > 0:
|
||||
id_to_parent[ob.id] = ob.parent_id
|
||||
|
||||
|
||||
if blender_booleans and ob.type == 'IfcOpeningElement':
|
||||
openings.append(ob.id)
|
||||
|
||||
faces = me.polygons if hasattr(me, 'polygons') else me.faces
|
||||
if len(faces) == len(matids):
|
||||
for face, matid in zip(faces, matids):
|
||||
face.material_index = matid + (1 if needs_default else 0)
|
||||
|
||||
|
||||
progress = iterator.progress() // 2
|
||||
if progress > old_progress:
|
||||
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
|
||||
@@ -168,13 +199,13 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
print("\rDone creating geometry" + " " * 30)
|
||||
|
||||
id_to_parent_temp = dict(id_to_parent)
|
||||
|
||||
|
||||
if process_relations:
|
||||
print("Processing relations...")
|
||||
|
||||
while len(id_to_parent_temp) and process_relations:
|
||||
id, parent_id = id_to_parent_temp.popitem()
|
||||
|
||||
|
||||
if parent_id in id_to_object:
|
||||
bob = id_to_object[parent_id][0]
|
||||
else:
|
||||
@@ -186,16 +217,17 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
nm = parent_ob.name if len(parent_ob.name) and use_names \
|
||||
else parent_ob.guid
|
||||
bob = bpy.data.objects.new(nm, None)
|
||||
|
||||
|
||||
mat = mathutils.Matrix((
|
||||
[m[0], m[1], m[2], 0],
|
||||
[m[3], m[4], m[5], 0],
|
||||
[m[6], m[7], m[8], 0],
|
||||
[m[9], m[10], m[11], 1]))
|
||||
if transpose_matrices: mat.transpose()
|
||||
if transpose_matrices:
|
||||
mat.transpose()
|
||||
id_to_matrix[parent_ob.id] = mat
|
||||
|
||||
bpy.context.scene.objects.link(bob)
|
||||
|
||||
rel_collection.objects.link(bob)
|
||||
|
||||
bob.ifc_id = parent_ob.id
|
||||
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
|
||||
@@ -218,13 +250,13 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
parent_matrix = id_to_matrix.get(parent_id, None)
|
||||
for ob in id_to_object[id]:
|
||||
if parent_matrix:
|
||||
ob.matrix_local = parent_matrix.inverted() * matrix
|
||||
ob.matrix_local = parent_matrix.inverted() @ matrix
|
||||
else:
|
||||
ob.matrix_world = matrix
|
||||
|
||||
|
||||
if process_relations:
|
||||
print("Done processing relations")
|
||||
|
||||
|
||||
for opening_id in openings:
|
||||
parent_id = id_to_parent[opening_id]
|
||||
if parent_id in id_to_object:
|
||||
@@ -233,9 +265,11 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
mod = parent_ob.modifiers.new("opening", "BOOLEAN")
|
||||
mod.operation = "DIFFERENCE"
|
||||
mod.object = opening_ob
|
||||
|
||||
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
|
||||
txt.from_string(iterator.getLog())
|
||||
|
||||
if hasattr(iterator, 'getLog'):
|
||||
# @todo
|
||||
txt = bpy.data.texts.new(f"{bpy.path.basename(filename)}.log")
|
||||
txt.from_string(iterator.getLog())
|
||||
|
||||
return True
|
||||
|
||||
@@ -245,42 +279,51 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
|
||||
bl_label = "Import .ifc file"
|
||||
|
||||
filename_ext = ".ifc"
|
||||
filter_glob = StringProperty(default="*.ifc", options={'HIDDEN'})
|
||||
filter_glob: StringProperty(default="*.ifc", options={'HIDDEN'})
|
||||
|
||||
use_names = BoolProperty(name="Use entity names",
|
||||
description="Use entity names rather than GlobalIds for objects",
|
||||
default=True)
|
||||
process_relations = BoolProperty(name="Process relations",
|
||||
description="Convert containment and aggregation" \
|
||||
" relations to parenting" \
|
||||
" (warning: may be slow on large files)",
|
||||
default=False)
|
||||
blender_booleans = BoolProperty(name="Use Blender booleans",
|
||||
description="Use Blender boolean modifiers for opening" \
|
||||
" elements",
|
||||
default=False)
|
||||
use_names: BoolProperty(name="Use entity names",
|
||||
description="Use entity names rather than "
|
||||
"GlobalIds for objects",
|
||||
default=True)
|
||||
process_relations: BoolProperty(name="Process relations",
|
||||
description="Convert containment and "
|
||||
"aggregation relations to parenting"
|
||||
" (warning: may be slow on large files)",
|
||||
default=False)
|
||||
blender_booleans: BoolProperty(name="Use Blender booleans",
|
||||
description="Use Blender boolean modifiers "
|
||||
"for opening elements",
|
||||
default=False)
|
||||
|
||||
def execute(self, context):
|
||||
if not import_ifc(self.filepath, self.use_names, self.process_relations, self.blender_booleans):
|
||||
if not import_ifc(self.filepath, self.use_names,
|
||||
self.process_relations, self.blender_booleans):
|
||||
self.report({'ERROR'},
|
||||
'Unable to parse .ifc file or no geometrical entities found'
|
||||
)
|
||||
'Unable to parse .ifc file or no geometrical entities found'
|
||||
)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(ImportIFC.bl_idname,
|
||||
text="Industry Foundation Classes (.ifc)")
|
||||
text="Industry Foundation Classes (.ifc)")
|
||||
|
||||
|
||||
classes = (
|
||||
ImportIFC,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_module(__name__)
|
||||
bpy.types.INFO_MT_file_import.append(menu_func_import)
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_module(__name__)
|
||||
bpy.types.INFO_MT_file_import.remove(menu_func_import)
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ColladaSerializer.h"
|
||||
|
||||
std::string collada_id(const std::string& s) {
|
||||
std::string id;
|
||||
id.reserve(s.size());
|
||||
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||
const std::string::value_type c = *it;
|
||||
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')) {
|
||||
id.push_back(c);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords /* = "XYZ" */) {
|
||||
COLLADASW::FloatSource source(mSW);
|
||||
source.setId(mesh_id + suffix);
|
||||
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
|
||||
source.setAccessorStride(strlen(coords));
|
||||
source.setAccessorCount(floats.size() / 3);
|
||||
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
|
||||
source.getParameterNameList().push_back(std::string(1, coords[i]));
|
||||
}
|
||||
source.prepareToAppendValues();
|
||||
for (std::vector<double>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
|
||||
source.appendValues(*it);
|
||||
}
|
||||
source.finish();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
|
||||
// The goal of the IfcGeom::Iterator is to filter out empty geometries, but
|
||||
// since this function would crash trying to deference the material_ids in
|
||||
// that case, a hard return statement is added just in case.
|
||||
if (indices.empty()) return;
|
||||
|
||||
openMesh(mesh_id);
|
||||
|
||||
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
|
||||
// IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
|
||||
const bool has_normals = !normals.empty();
|
||||
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
|
||||
if (has_normals) {
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
|
||||
}
|
||||
|
||||
COLLADASW::VerticesElement vertices(mSW);
|
||||
vertices.setId(mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX );
|
||||
vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX));
|
||||
vertices.add();
|
||||
|
||||
std::vector<int>::const_iterator index_range_start = indices.begin();
|
||||
std::vector<int>::const_iterator material_it = material_ids.begin();
|
||||
int previous_material_id = -1;
|
||||
for (std::vector<int>::const_iterator it = indices.begin(); ; it += 3) {
|
||||
const int current_material_id = *(material_it++);
|
||||
const int num_triangles = std::distance(index_range_start, it) / 3;
|
||||
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == indices.end())) {
|
||||
COLLADASW::Triangles triangles(mSW);
|
||||
triangles.setMaterial(materials[previous_material_id].name());
|
||||
triangles.setCount(num_triangles);
|
||||
int offset = 0;
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) );
|
||||
if (has_normals) {
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) );
|
||||
}
|
||||
triangles.prepareToAppendValues();
|
||||
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
|
||||
const int idx = *jt;
|
||||
if (has_normals) {
|
||||
triangles.appendValues(idx, idx);
|
||||
} else {
|
||||
triangles.appendValues(idx);
|
||||
}
|
||||
}
|
||||
triangles.finish();
|
||||
index_range_start = it;
|
||||
}
|
||||
previous_material_id = current_material_id;
|
||||
if (it == indices.end()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closeMesh();
|
||||
closeGeometry();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix) {
|
||||
if (!scene_opened) {
|
||||
openVisualScene(scene_id);
|
||||
scene_opened = true;
|
||||
}
|
||||
|
||||
COLLADASW::Node node(mSW);
|
||||
node.setNodeId(node_id);
|
||||
node.setNodeName(node_name);
|
||||
node.setType(COLLADASW::Node::NODE);
|
||||
|
||||
// The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement.
|
||||
// Note that this placement is absolute, ie it is multiplied with all parent placements.
|
||||
double matrix_array[4][4] = {
|
||||
{matrix[0], matrix[3], matrix[6], matrix[ 9]},
|
||||
{matrix[1], matrix[4], matrix[7], matrix[10]},
|
||||
{matrix[2], matrix[5], matrix[8], matrix[11]},
|
||||
{ 0, 0, 0, 1}
|
||||
};
|
||||
|
||||
node.start();
|
||||
node.addMatrix(matrix_array);
|
||||
COLLADASW::InstanceGeometry instanceGeometry(mSW);
|
||||
instanceGeometry.setUrl ("#" + geom_name);
|
||||
for (std::vector<std::string>::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) {
|
||||
COLLADASW::InstanceMaterial material (*it, "#" + *it);
|
||||
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
|
||||
}
|
||||
instanceGeometry.add();
|
||||
node.end();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaScene::write() {
|
||||
if (scene_opened) {
|
||||
closeVisualScene();
|
||||
closeLibrary();
|
||||
|
||||
COLLADASW::Scene scene (mSW, COLLADASW::URI ("#" + scene_id));
|
||||
scene.add();
|
||||
}
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) {
|
||||
openEffect(collada_id(material.name()) + "-fx");
|
||||
COLLADASW::EffectProfile effect(mSW);
|
||||
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
|
||||
if (material.hasDiffuse()) {
|
||||
const double* diffuse = material.diffuse();
|
||||
effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(diffuse[0],diffuse[1],diffuse[2])));
|
||||
}
|
||||
if (material.hasSpecular()) {
|
||||
const double* specular = material.specular();
|
||||
effect.setSpecular(COLLADASW::ColorOrTexture(COLLADASW::Color(specular[0],specular[1],specular[2])));
|
||||
}
|
||||
if (material.hasSpecularity()) {
|
||||
effect.setShininess(material.specularity());
|
||||
}
|
||||
if (material.hasTransparency()) {
|
||||
const double transparency = material.transparency();
|
||||
if (transparency > 0) {
|
||||
// The default opacity mode for Collada is A_ONE, which apparently indicates a
|
||||
// transparency value of 1 to be fully opaque. Hence transparency is inverted.
|
||||
effect.setTransparency(1.0 - transparency);
|
||||
}
|
||||
}
|
||||
addEffectProfile(effect);
|
||||
closeEffect();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
|
||||
if (!contains(material)) {
|
||||
effects.write(material);
|
||||
materials.push_back(material);
|
||||
}
|
||||
}
|
||||
|
||||
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) {
|
||||
return std::find(materials.begin(), materials.end(), material) != materials.end();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
|
||||
effects.close();
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
|
||||
const std::string& material_name = collada_id((*it).name());
|
||||
openMaterial(material_name);
|
||||
addInstanceEffect("#" + material_name + "-fx");
|
||||
closeMaterial();
|
||||
}
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) {
|
||||
stream.startDocument();
|
||||
|
||||
COLLADASW::Asset asset(&stream);
|
||||
asset.getContributor().mAuthoringTool = std::string("IfcOpenShell ") + IFCOPENSHELL_VERSION;
|
||||
asset.setUnit(unit_name, unit_magnitude);
|
||||
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
|
||||
asset.add();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
|
||||
std::vector<std::string> material_references;
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
|
||||
const IfcGeom::Material& material = *it;
|
||||
if (!materials.contains(material)) {
|
||||
materials.add(material);
|
||||
}
|
||||
material_references.push_back(collada_id(material.name()));
|
||||
}
|
||||
deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references));
|
||||
}
|
||||
|
||||
const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const {
|
||||
std::stringstream ss;
|
||||
if (!this->name.empty()) {
|
||||
ss << this->obj_id << "_" << this->name;
|
||||
} else {
|
||||
ss << this->guid;
|
||||
}
|
||||
return collada_id(ss.str());
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
// In fact due the XML based nature of Collada and its dependency on library nodes,
|
||||
// only at this point all objects are written to the stream.
|
||||
materials.write();
|
||||
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
|
||||
const std::string object_name = it->Name();
|
||||
geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, it->material_ids, it->materials);
|
||||
}
|
||||
geometries.close();
|
||||
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
|
||||
const std::string object_name = it->Name();
|
||||
scene.add(object_name + "-instance", object_name, object_name, it->material_references, it->matrix);
|
||||
}
|
||||
scene.write();
|
||||
stream.endDocument();
|
||||
}
|
||||
|
||||
bool ColladaSerializer::ready() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ColladaSerializer::writeHeader() {
|
||||
exporter.startDocument(unit_name, unit_magnitude);
|
||||
}
|
||||
|
||||
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
|
||||
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
|
||||
exporter.write(o->guid(), o->name(), o->type(), o->id(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.material_ids(), mesh.materials());
|
||||
}
|
||||
|
||||
void ColladaSerializer::finalize() {
|
||||
exporter.endDocument();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,165 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
|
||||
#ifndef COLLADASERIALIZER_H
|
||||
#define COLLADASERIALIZER_H
|
||||
|
||||
#include <COLLADASWStreamWriter.h>
|
||||
#include <COLLADASWPrimitves.h>
|
||||
#include <COLLADASWLibraryGeometries.h>
|
||||
#include <COLLADASWSource.h>
|
||||
#include <COLLADASWScene.h>
|
||||
#include <COLLADASWNode.h>
|
||||
#include <COLLADASWInstanceGeometry.h>
|
||||
#include <COLLADASWLibraryVisualScenes.h>
|
||||
#include <COLLADASWLibraryEffects.h>
|
||||
#include <COLLADASWLibraryMaterials.h>
|
||||
#include <COLLADASWBaseInputElement.h>
|
||||
#include <COLLADASWAsset.h>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
|
||||
class ColladaSerializer : public GeometrySerializer
|
||||
{
|
||||
private:
|
||||
class ColladaExporter
|
||||
{
|
||||
private:
|
||||
class ColladaGeometries : public COLLADASW::LibraryGeometries
|
||||
{
|
||||
public:
|
||||
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryGeometries(&stream)
|
||||
{}
|
||||
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
|
||||
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void close();
|
||||
};
|
||||
class ColladaScene : public COLLADASW::LibraryVisualScenes
|
||||
{
|
||||
private:
|
||||
const std::string scene_id;
|
||||
bool scene_opened;
|
||||
public:
|
||||
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryVisualScenes(&stream)
|
||||
, scene_id(scene_id)
|
||||
, scene_opened(false)
|
||||
{}
|
||||
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix);
|
||||
void write();
|
||||
};
|
||||
class ColladaMaterials : public COLLADASW::LibraryMaterials
|
||||
{
|
||||
private:
|
||||
class ColladaEffects : public COLLADASW::LibraryEffects
|
||||
{
|
||||
public:
|
||||
explicit ColladaEffects(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryEffects(&stream)
|
||||
{}
|
||||
void write(const IfcGeom::Material& material);
|
||||
void close();
|
||||
};
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
ColladaEffects effects;
|
||||
public:
|
||||
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryMaterials(&stream)
|
||||
, effects(stream)
|
||||
{}
|
||||
void add(const IfcGeom::Material& material);
|
||||
bool contains(const IfcGeom::Material& material);
|
||||
void write();
|
||||
};
|
||||
class DeferredObject {
|
||||
public:
|
||||
std::string guid, name, type;
|
||||
int obj_id;
|
||||
std::vector<double> matrix;
|
||||
std::vector<double> vertices;
|
||||
std::vector<double> normals;
|
||||
std::vector<int> indices;
|
||||
std::vector<int> material_ids;
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
std::vector<std::string> material_references;
|
||||
DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices,
|
||||
const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids,
|
||||
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
|
||||
: guid(guid)
|
||||
, name(name)
|
||||
, type(type)
|
||||
, obj_id(obj_id)
|
||||
, matrix(matrix)
|
||||
, vertices(vertices)
|
||||
, normals(normals)
|
||||
, indices(indices)
|
||||
, material_ids(material_ids)
|
||||
, materials(materials)
|
||||
, material_references(material_references)
|
||||
{}
|
||||
const std::string Name() const;
|
||||
};
|
||||
COLLADABU::NativeString filename;
|
||||
COLLADASW::StreamWriter stream;
|
||||
ColladaGeometries geometries;
|
||||
ColladaScene scene;
|
||||
ColladaMaterials materials;
|
||||
public:
|
||||
ColladaExporter(const std::string& scene_name, const std::string& fn)
|
||||
: filename(fn.c_str())
|
||||
, stream(filename)
|
||||
, geometries(stream)
|
||||
, scene(scene_name, stream)
|
||||
, materials(stream)
|
||||
{}
|
||||
std::vector<DeferredObject> deferreds;
|
||||
virtual ~ColladaExporter() {}
|
||||
void startDocument(const std::string& unit_name, float unit_magnitude);
|
||||
void write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void endDocument();
|
||||
};
|
||||
ColladaExporter exporter;
|
||||
std::string unit_name;
|
||||
float unit_magnitude;
|
||||
public:
|
||||
ColladaSerializer(const std::string& dae_filename)
|
||||
: GeometrySerializer()
|
||||
, exporter("IfcOpenShell", dae_filename)
|
||||
{}
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void write(const IfcGeom::TriangulationElement<double>* o);
|
||||
void write(const IfcGeom::BRepElement<double>* o) {}
|
||||
void finalize();
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
unit_name = name;
|
||||
unit_magnitude = magnitude;
|
||||
}
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+1203
-209
File diff suppressed because it is too large
Load Diff
@@ -1,78 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file defines default materials for several IFC datatypes *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SURFACESTYLE_H
|
||||
#define SURFACESTYLE_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <array>
|
||||
|
||||
class SurfaceStyle {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
std::array<double, 3> data;
|
||||
public:
|
||||
ColorComponent(double r, double g, double b) {
|
||||
data[0] = r; data[1] = g; data[2] = b;
|
||||
}
|
||||
const double& R() const { return data[0]; }
|
||||
const double& G() const { return data[1]; }
|
||||
const double& B() const { return data[2]; }
|
||||
double& R() { return data[0]; }
|
||||
double& G() { return data[1]; }
|
||||
double& B() { return data[2]; }
|
||||
};
|
||||
private:
|
||||
std::string name;
|
||||
ColorComponent diffuse, specular, ambient;
|
||||
double transparency;
|
||||
double specularity;
|
||||
public:
|
||||
SurfaceStyle(const std::string& name,
|
||||
double dr = 0.7, double dg = 0.7, double db = 0.7,
|
||||
double sr = 0.2, double sg = 0.2, double sb = 0.2,
|
||||
double ar = 0.1, double ag = 0.1, double ab = 0.1,
|
||||
double Ns = 10.0, double Tr = 1.0)
|
||||
: name(name)
|
||||
, diffuse(dr, dg, db)
|
||||
, specular(sr, sg, sb)
|
||||
, ambient(ar, ag, ab)
|
||||
, transparency(Tr)
|
||||
, specularity(Ns)
|
||||
{}
|
||||
const std::string& Name() const { return name; }
|
||||
const ColorComponent& Diffuse() const { return diffuse; }
|
||||
const ColorComponent& Specular() const { return specular; }
|
||||
const ColorComponent& Ambient() const { return ambient; }
|
||||
double Transparency() const { return transparency; }
|
||||
double Specularity() const { return specularity; }
|
||||
};
|
||||
|
||||
SurfaceStyle GetDefaultMaterial(const std::string& s);
|
||||
|
||||
#endif
|
||||
@@ -1,257 +0,0 @@
|
||||
#include <map>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/xml_parser.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#include "XmlSerializer.h"
|
||||
|
||||
using boost::property_tree::ptree;
|
||||
using namespace IfcSchema;
|
||||
|
||||
static std::map<std::string, std::string> argument_name_map;
|
||||
|
||||
// Format an IFC attribute and maybe returns as string. Only literal scalar
|
||||
// values are converted. Things like entity instances and lists are omitted.
|
||||
boost::optional<std::string> format_attribute(const Argument* argument, IfcUtil::ArgumentType argument_type) {
|
||||
boost::optional<std::string> value;
|
||||
switch(argument_type) {
|
||||
case IfcUtil::Argument_BOOL: {
|
||||
const bool b = *argument;
|
||||
value = b ? "true" : "false";
|
||||
break; }
|
||||
case IfcUtil::Argument_DOUBLE: {
|
||||
const double d = *argument;
|
||||
std::stringstream stream;
|
||||
stream << d;
|
||||
value = stream.str();
|
||||
break; }
|
||||
case IfcUtil::Argument_STRING:
|
||||
case IfcUtil::Argument_ENUMERATION: {
|
||||
value = static_cast<std::string>(*argument);
|
||||
break; }
|
||||
case IfcUtil::Argument_INT: {
|
||||
const int v = *argument;
|
||||
std::stringstream stream;
|
||||
stream << v;
|
||||
value = stream.str();
|
||||
break; }
|
||||
case IfcUtil::Argument_ENTITY: {
|
||||
IfcUtil::IfcBaseClass* e = *argument;
|
||||
if (Type::IsSimple(e->type())) {
|
||||
IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e;
|
||||
value = format_attribute(f->getArgument(0), f->getArgumentType(0));
|
||||
} else if (e->is(IfcSchema::Type::IfcSIUnit) || e->is(IfcSchema::Type::IfcConversionBasedUnit)) {
|
||||
// Some string concatenation to have a unit name as a XML attribute.
|
||||
|
||||
std::string unit_name;
|
||||
|
||||
if (e->is(IfcSchema::Type::IfcSIUnit)) {
|
||||
IfcSchema::IfcSIUnit* unit = (IfcSchema::IfcSIUnit*) e;
|
||||
unit_name = IfcSchema::IfcSIUnitName::ToString(unit->Name());
|
||||
if (unit->hasPrefix()) {
|
||||
unit_name = IfcSchema::IfcSIPrefix::ToString(unit->Prefix()) + unit_name;
|
||||
}
|
||||
} else {
|
||||
IfcSchema::IfcConversionBasedUnit* unit = (IfcSchema::IfcConversionBasedUnit*) e;
|
||||
unit_name = unit->Name();
|
||||
}
|
||||
|
||||
for (std::string::iterator c = unit_name.begin(); c != unit_name.end(); ++c) *c = tolower(*c);
|
||||
|
||||
value = unit_name;
|
||||
}
|
||||
break; }
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Formats an entity instances as a ptree node, and insert into the DOM. Recurses
|
||||
// over the entity attributes and writes them as xml attributes of the node.
|
||||
ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& tree, bool as_link = false) {
|
||||
ptree child;
|
||||
const unsigned n = instance->getArgumentCount();
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
const Argument* argument = instance->getArgument(i);
|
||||
if (argument->isNull()) continue;
|
||||
|
||||
std::string argument_name = instance->getArgumentName(i);
|
||||
std::map<std::string, std::string>::const_iterator argument_name_it;
|
||||
argument_name_it = argument_name_map.find(argument_name);
|
||||
if (argument_name_it != argument_name_map.end()) {
|
||||
argument_name = argument_name_it->second;
|
||||
}
|
||||
const IfcUtil::ArgumentType argument_type = instance->getArgumentType(i);
|
||||
|
||||
boost::optional<std::string> value;
|
||||
try {
|
||||
value = format_attribute(argument, argument_type);
|
||||
} catch (...) {}
|
||||
|
||||
if (value) {
|
||||
if (as_link) {
|
||||
if (argument_name == "id") {
|
||||
child.put("<xmlattr>.xlink:href", std::string("#") + *value);
|
||||
}
|
||||
} else {
|
||||
std::stringstream stream;
|
||||
stream << "<xmlattr>." << argument_name;
|
||||
child.put(stream.str(), *value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tree.add_child(Type::ToString(instance->type()), child);
|
||||
}
|
||||
|
||||
// A function to be called recursively. Template specialization is used
|
||||
// to descend into decomposition, containment and property relationships.
|
||||
template <typename A>
|
||||
void descend(A* instance, ptree& tree) {
|
||||
format_entity_instance(instance, tree);
|
||||
}
|
||||
|
||||
// Returns related entity instances using IFC's objectified relationship
|
||||
// model. The second and third argument require a member function pointer.
|
||||
template <typename T, typename U, typename V, typename F, typename G>
|
||||
typename V::list::ptr get_related(T* t, F f, G g) {
|
||||
typename U::list::ptr li = (*t.*f)()->template as<U>();
|
||||
typename V::list::ptr acc(new typename V::list);
|
||||
for (typename U::list::it it = li->begin(); it != li->end(); ++it) {
|
||||
U* u = *it;
|
||||
acc->push((*u.*g)());
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
// Descends into the tree by recursing into IfcRelContainedInSpatialStructure,
|
||||
// IfcRelDecomposes and IfcRelDefinesByProperties relations.
|
||||
template <>
|
||||
void descend(IfcProduct* product, ptree& tree) {
|
||||
ptree& child = format_entity_instance(product, tree);
|
||||
|
||||
if (product->is(Type::IfcSpatialStructureElement)) {
|
||||
IfcSpatialStructureElement* structure = (IfcSpatialStructureElement*) product;
|
||||
|
||||
IfcProduct::list::ptr elements = get_related
|
||||
<IfcSpatialStructureElement, IfcRelContainedInSpatialStructure, IfcProduct>
|
||||
(structure, &IfcSpatialStructureElement::ContainsElements, &IfcRelContainedInSpatialStructure::RelatedElements);
|
||||
|
||||
for (IfcProduct::list::it it = elements->begin(); it != elements->end(); ++it) {
|
||||
descend(*it, child);
|
||||
}
|
||||
}
|
||||
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
|
||||
(product, &IfcProduct::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
|
||||
|
||||
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
|
||||
IfcObjectDefinition* ob = *it;
|
||||
if (ob->is(Type::IfcSpatialStructureElement)) {
|
||||
descend((IfcProduct*)ob, child);
|
||||
} else {
|
||||
descend(ob, child);
|
||||
}
|
||||
}
|
||||
|
||||
IfcPropertySetDefinition::list::ptr property_sets = get_related
|
||||
<IfcProduct, IfcRelDefinesByProperties, IfcPropertySetDefinition>
|
||||
(product, &IfcProduct::IsDefinedBy, &IfcRelDefinesByProperties::RelatingPropertyDefinition);
|
||||
|
||||
for (IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
|
||||
IfcPropertySetDefinition* pset = *it;
|
||||
if (pset->is(Type::IfcPropertySet)) {
|
||||
format_entity_instance(pset, child, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Descends into the tree by recursing into IfcRelDecomposes relations.
|
||||
template <>
|
||||
void descend(IfcProject* project, ptree& tree) {
|
||||
ptree& child = format_entity_instance(project, tree);
|
||||
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcProject, IfcRelDecomposes, IfcObjectDefinition>
|
||||
(project, &IfcProject::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
|
||||
|
||||
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
|
||||
IfcObjectDefinition* ob = *it;
|
||||
if (ob->is(Type::IfcSpatialStructureElement)) {
|
||||
descend((IfcProduct*)ob, child);
|
||||
} else {
|
||||
descend(ob, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Format IfcProperty instances and insert into the DOM. IfcComplexProperties are flattened out.
|
||||
void format_properties(IfcProperty::list::ptr properties, ptree& node) {
|
||||
for (IfcProperty::list::it it = properties->begin(); it != properties->end(); ++it) {
|
||||
IfcProperty* p = *it;
|
||||
if (p->is(Type::IfcComplexProperty)) {
|
||||
IfcComplexProperty* complex = (IfcComplexProperty*) p;
|
||||
format_properties(complex->HasProperties(), node);
|
||||
} else {
|
||||
format_entity_instance(p, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XmlSerializer::finalize() {
|
||||
argument_name_map.insert(std::make_pair("GlobalId", "id"));
|
||||
|
||||
IfcProject::list::ptr projects = file->entitiesByType<IfcProject>();
|
||||
if (projects->size() != 1) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Expected a single IfcProject");
|
||||
return;
|
||||
}
|
||||
IfcProject* project = *projects->begin();
|
||||
|
||||
ptree root, header, decomposition, properties;
|
||||
|
||||
// Write the SPF header as XML nodes.
|
||||
BOOST_FOREACH(const std::string& s, file->header().file_description().description()) {
|
||||
header.add_child("file_description.description", ptree(s));
|
||||
}
|
||||
BOOST_FOREACH(const std::string& s, file->header().file_name().author()) {
|
||||
header.add_child("file_name.author", ptree(s));
|
||||
}
|
||||
BOOST_FOREACH(const std::string& s, file->header().file_name().organization()) {
|
||||
header.add_child("file_name.organization", ptree(s));
|
||||
}
|
||||
BOOST_FOREACH(const std::string& s, file->header().file_schema().schema_identifiers()) {
|
||||
header.add_child("file_schema.schema_identifiers", ptree(s));
|
||||
}
|
||||
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
|
||||
header.put("file_name.name", file->header().file_name().name());
|
||||
header.put("file_name.time_stamp", file->header().file_name().time_stamp());
|
||||
header.put("file_name.preprocessor_version", file->header().file_name().preprocessor_version());
|
||||
header.put("file_name.originating_system", file->header().file_name().originating_system());
|
||||
header.put("file_name.authorization", file->header().file_name().authorization());
|
||||
|
||||
// Descend into the decomposition structure of the IFC file.
|
||||
descend(project, decomposition);
|
||||
|
||||
// Write all property sets and values as XML nodes.
|
||||
IfcPropertySet::list::ptr psets = file->entitiesByType<IfcPropertySet>();
|
||||
for (IfcPropertySet::list::it it = psets->begin(); it != psets->end(); ++it) {
|
||||
IfcPropertySet* pset = *it;
|
||||
ptree& node = format_entity_instance(pset, properties);
|
||||
format_properties(pset->HasProperties(), node);
|
||||
}
|
||||
|
||||
root.add_child("ifc.header", header);
|
||||
root.add_child("ifc.properties", properties);
|
||||
root.add_child("ifc.decomposition", decomposition);
|
||||
|
||||
root.put("ifc.<xmlattr>.xmlns:xlink", "http://www.w3.org/1999/xlink");
|
||||
|
||||
#if BOOST_VERSION >= 105600
|
||||
boost::property_tree::xml_writer_settings<ptree::key_type> settings = boost::property_tree::xml_writer_make_settings<ptree::key_type>('\t', 1);
|
||||
#else
|
||||
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
|
||||
#endif
|
||||
boost::property_tree::write_xml(xml_filename, root, std::locale(), settings);
|
||||
}
|
||||
@@ -4,6 +4,8 @@ the IFC schema and will most likely fail on any other Express schema.
|
||||
|
||||
The code can be invoked in the following way and results in two header files
|
||||
and a single implementation file named according to the schema name in the
|
||||
Express file. A python 3 interpreter with the pyparsing library is required.
|
||||
Express file. A python 3 interpreter with the pyparsing [1] library is required.
|
||||
|
||||
$ python bootstrap.py express.bnf > express_parser.py && python express_parser.py IFC2X3_TC1.exp
|
||||
|
||||
[1] http://pyparsing.wikispaces.com/Download+and+Installation
|
||||
|
||||
@@ -19,8 +19,14 @@
|
||||
|
||||
import sys
|
||||
import string
|
||||
import operator
|
||||
import itertools
|
||||
|
||||
from pyparsing import *
|
||||
|
||||
try: from functools import reduce
|
||||
except: pass
|
||||
|
||||
class Expression:
|
||||
def __init__(self, contents):
|
||||
self.contents = contents[0]
|
||||
@@ -56,12 +62,12 @@ class Keyword:
|
||||
class Terminal:
|
||||
def __init__(self, contents):
|
||||
self.contents = contents[0]
|
||||
def __repr__(self):
|
||||
s = self.contents
|
||||
is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
|
||||
self.is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
|
||||
all(c in alphanums+"_" for c in s[1:-1])
|
||||
ty = "CaselessKeyword" if is_keyword else "CaselessLiteral"
|
||||
return "%s(%s)" % (ty, s)
|
||||
def __repr__(self):
|
||||
ty = "CaselessKeyword" if self.is_keyword else "CaselessLiteral"
|
||||
return "%s(%s)" % (ty, self.contents)
|
||||
|
||||
|
||||
LPAREN = Suppress("(")
|
||||
@@ -94,16 +100,16 @@ grammar.ignore(HASH + restOfLine)
|
||||
|
||||
express = grammar.parseFile(sys.argv[1])
|
||||
|
||||
def find_keywords(expr, li = None):
|
||||
def find_bytype(expr, ty, li = None):
|
||||
if li is None: li = []
|
||||
if isinstance(expr, Term):
|
||||
expr = expr.contents
|
||||
if isinstance(expr, Keyword):
|
||||
li.append(repr(expr))
|
||||
return li
|
||||
if isinstance(expr, ty):
|
||||
li.append(expr)
|
||||
return set(li)
|
||||
elif isinstance(expr, Expression):
|
||||
for term in expr:
|
||||
find_keywords(term, li)
|
||||
find_bytype(term, ty, li)
|
||||
return set(li)
|
||||
|
||||
actions = {
|
||||
@@ -115,13 +121,16 @@ actions = {
|
||||
'general_aggregation_types' : "lambda t: AggregationType(t)",
|
||||
'select_type' : "lambda t: SelectType(t)",
|
||||
'binary_type' : "lambda t: BinaryType(t)",
|
||||
'subtype_declaration' : "lambda t: SubtypeExpression(t)",
|
||||
'subtype_declaration' : "lambda t: SubTypeExpression(t)",
|
||||
'supertype_constraint' : "lambda t: SuperTypeExpression(t)",
|
||||
'derive_clause' : "lambda t: AttributeList('derive', t)",
|
||||
'derived_attr' : "lambda t: DerivedAttribute(t)",
|
||||
'inverse_clause' : "lambda t: AttributeList('inverse', t)",
|
||||
'inverse_attr' : "lambda t: InverseAttribute(t)",
|
||||
'bound_spec' : "lambda t: BoundSpecification(t)",
|
||||
'explicit_attr' : "lambda t: ExplicitAttribute(t)",
|
||||
'width_spec' : "lambda t: WidthSpec(t)",
|
||||
'string_type' : "lambda t: StringType(t)",
|
||||
}
|
||||
|
||||
to_emit = set(id for id, expr in express)
|
||||
@@ -129,18 +138,22 @@ emitted = set()
|
||||
to_combine = set(["simple_id"])
|
||||
to_ignore = set(["where_clause", "supertype_constraint", "unique_clause"])
|
||||
statements = []
|
||||
|
||||
terminals = reduce(lambda x,y: x | y, (find_bytype(e, Terminal) for id, e in express))
|
||||
keywords = list(filter(operator.attrgetter('is_keyword'), terminals))
|
||||
negated_keywords = map(lambda s: "~%s" % s, keywords)
|
||||
|
||||
while True:
|
||||
emitted_in_loop = set()
|
||||
for id, expr in express:
|
||||
kws = find_keywords(expr)
|
||||
kws = map(repr, find_bytype(expr, Keyword))
|
||||
found = [k in emitted for k in kws]
|
||||
if id in to_emit and all(found):
|
||||
emitted_in_loop.add(id)
|
||||
emitted.add(id)
|
||||
stmt = "(%s)" % expr
|
||||
if id in to_combine:
|
||||
stmt = "originalTextFor(Combine%s)" % stmt
|
||||
stmt = " + ".join(itertools.chain(negated_keywords, ("originalTextFor(Combine%s)" % stmt,)))
|
||||
if id in actions:
|
||||
stmt = "%s.setParseAction(%s)" % (stmt, actions[id])
|
||||
statements.append("%s = %s" % (id, stmt))
|
||||
@@ -158,29 +171,42 @@ for id in to_emit:
|
||||
stmt = "Suppress%s" % stmt
|
||||
statements.append("%s << %s" % (id, stmt))
|
||||
|
||||
print ("""import sys
|
||||
from pyparsing import *
|
||||
from nodes import *
|
||||
print ("""import os
|
||||
import sys
|
||||
import pickle
|
||||
|
||||
%s
|
||||
cache_file = sys.argv[1] + ".cache.dat"
|
||||
if os.path.exists(cache_file):
|
||||
with open(cache_file, "rb") as f:
|
||||
mapping = pickle.load(f)
|
||||
schema = mapping.schema
|
||||
else:
|
||||
from pyparsing import *
|
||||
from nodes import *
|
||||
|
||||
import schema
|
||||
import mapping
|
||||
|
||||
%s
|
||||
|
||||
import schema
|
||||
import mapping
|
||||
syntax.ignore("--" + restOfLine)
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(sys.argv[1])
|
||||
schema = schema.Schema(ast)
|
||||
mapping = mapping.Mapping(schema)
|
||||
|
||||
with open(cache_file, "wb") as f:
|
||||
pickle.dump(mapping, f, protocol=0)
|
||||
|
||||
import header
|
||||
import enum_header
|
||||
import implementation
|
||||
import latebound_header
|
||||
import latebound_implementation
|
||||
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(sys.argv[1])
|
||||
schema = schema.Schema(ast)
|
||||
mapping = mapping.Mapping(schema)
|
||||
import schema_class
|
||||
|
||||
header.Header(mapping).emit()
|
||||
enum_header.EnumHeader(mapping).emit()
|
||||
implementation.Implementation(mapping).emit()
|
||||
latebound_header.LateBoundHeader(mapping).emit()
|
||||
latebound_implementation.LateBoundImplementation(mapping).emit()
|
||||
"""%('\n'.join(statements)))
|
||||
schema_class.SchemaClass(mapping).emit()
|
||||
|
||||
sys.stdout.write(schema.name)
|
||||
"""%('\n '.join(statements)))
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
class Base(object):
|
||||
"""
|
||||
A base class for all code generation classes. Currently only working around
|
||||
some python 2/3 incompatibilities in terms of unicode file handling.
|
||||
"""
|
||||
def emit(self):
|
||||
import platform
|
||||
if tuple(map(int, platform.python_version_tuple())) < (2, 8):
|
||||
from io import open as unicode_open
|
||||
unicode_type = unicode
|
||||
else:
|
||||
unicode_open = open
|
||||
unicode_type = lambda x, *args, **kwargs: x
|
||||
f = unicode_open(self.file_name, 'w', encoding='utf-8')
|
||||
f.write(unicode_type(repr(self), encoding='utf-8', errors='ignore'))
|
||||
f.close()
|
||||
@@ -27,18 +27,25 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import re,csv
|
||||
import re
|
||||
import os
|
||||
import csv
|
||||
|
||||
from schema import OrderedCaseInsensitiveDict
|
||||
|
||||
try: from html.entities import entitydefs
|
||||
except: from htmlentitydefs import entitydefs
|
||||
|
||||
name_to_oid = {}
|
||||
make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn)
|
||||
|
||||
name_to_oid = OrderedCaseInsensitiveDict()
|
||||
oid_to_desc = {}
|
||||
oid_to_name = {}
|
||||
oid_to_pid = {}
|
||||
regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+']],['','\n\n',' ']))
|
||||
|
||||
definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv']
|
||||
definition_files = map(make_absolute, definition_files)
|
||||
for fn in definition_files:
|
||||
with open(fn) as f:
|
||||
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
@@ -46,15 +53,15 @@ for fn in definition_files:
|
||||
oid_to_name[oid] = name
|
||||
oid_to_desc[oid] = desc
|
||||
|
||||
with open('DocEntityAttributes.csv') as f:
|
||||
with open(make_absolute('DocEntityAttributes.csv')) as f:
|
||||
for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
oid_to_pid[oid] = pid
|
||||
|
||||
with open('DocAttribute.csv') as f:
|
||||
with open(make_absolute('DocAttribute.csv')) as f:
|
||||
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
pid = oid_to_pid[oid]
|
||||
pname = oid_to_name[pid]
|
||||
name_to_oid[(pname, name)] = oid
|
||||
name_to_oid[".".join((pname, name))] = oid
|
||||
oid_to_desc[oid] = desc
|
||||
|
||||
def description(item):
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
###############################################################################
|
||||
|
||||
import templates
|
||||
import codegen
|
||||
|
||||
class EnumHeader:
|
||||
class EnumHeader(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
|
||||
|
||||
@@ -30,9 +31,9 @@ class EnumHeader:
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%senum.h'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%senum.h'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# Taken from http://sourceforge.net/p/exp-engine/expresso/ci/master/tree/docs/iso-10303-11--2004.bnf
|
||||
|
||||
ABS = "abs" .
|
||||
ABSTRACT = "abstract" .
|
||||
ACOS = "acos" .
|
||||
@@ -202,7 +200,7 @@ constructed_types = enumeration_type | select_type .
|
||||
declaration = entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl .
|
||||
derived_attr = attribute_decl ":" parameter_type ":=" expression ";" .
|
||||
derive_clause = DERIVE derived_attr { derived_attr } .
|
||||
domain_rule = rule_label_id ":" expression .
|
||||
domain_rule = [ rule_label_id ":" ] expression .
|
||||
element = expression [ ":" repetition ] .
|
||||
entity_body = { explicit_attr } [ derive_clause ] [ inverse_clause ] [ unique_clause ] [ where_clause ] .
|
||||
entity_constructor = entity_ref "(" [ expression { "," expression } ] ")" .
|
||||
@@ -334,7 +332,7 @@ type_label_id = simple_id .
|
||||
unary_op = "+" | "-" | NOT .
|
||||
underlying_type = constructed_types | concrete_types .
|
||||
unique_clause = UNIQUE unique_rule ";" { unique_rule ";" } .
|
||||
unique_rule = rule_label_id ":" referenced_attribute { "," referenced_attribute } .
|
||||
unique_rule = [ rule_label_id ":" ] referenced_attribute { "," referenced_attribute } .
|
||||
until_control = UNTIL logical_expression .
|
||||
use_clause = USE FROM schema_ref [ "(" named_type_or_rename { "," named_type_or_rename } ")" ] ";" .
|
||||
variable_id = simple_id .
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import operator
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
import documentation
|
||||
|
||||
class Header:
|
||||
class Header(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
declarations = []
|
||||
|
||||
@@ -40,15 +43,18 @@ class Header:
|
||||
emitted_simpletypes = set()
|
||||
while len(emitted_simpletypes) < len(mapping.schema.simpletypes):
|
||||
for name, type in mapping.schema.simpletypes.items():
|
||||
if name in emitted_simpletypes: continue
|
||||
if name.lower() in emitted_simpletypes: continue
|
||||
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
|
||||
attr_type = mapping.make_argument_type(type)
|
||||
superclass = mapping.simple_type_parent(name)
|
||||
if superclass is None:
|
||||
superclass = "IfcUtil::IfcBaseType"
|
||||
elif superclass not in emitted_simpletypes:
|
||||
elif superclass.lower() not in emitted_simpletypes:
|
||||
continue
|
||||
emitted_simpletypes.add(name)
|
||||
else:
|
||||
# Case normalize
|
||||
superclass = [k for k in mapping.schema.simpletypes.keys() if k.lower() == superclass.lower()][0]
|
||||
emitted_simpletypes.add(name.lower())
|
||||
write(templates.simpletype, name=name, type=type_str, attr_type=attr_type, superclass=superclass)
|
||||
|
||||
class_definitions = []
|
||||
@@ -59,14 +65,14 @@ class Header:
|
||||
emitted_entities = set()
|
||||
while len(emitted_entities) < len(mapping.schema.entities):
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if name in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
|
||||
if name.lower() in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(map(str.lower, type.supertypes)) <= emitted_entities:
|
||||
attr_lines = []
|
||||
def write_method(attr):
|
||||
if attr.optional:
|
||||
attr_lines.append(templates.optional_attribute_description % (attr.name, name))
|
||||
attr_lines.append("bool has%s() const;"%(attr.name))
|
||||
attr_lines.extend(["/// %s"%d for d in documentation.description((name, attr.name))])
|
||||
attr_lines.extend(["/// %s"%d for d in documentation.description(".".join((name, attr.name)))])
|
||||
type_str = mapping.get_parameter_type(attr, allow_optional=False, allow_entities=False)
|
||||
if mapping.make_argument_type(attr) != "IfcUtil::Argument_UNKNOWN":
|
||||
attr_lines.append("%s %s() const;"%(type_str, attr.name))
|
||||
@@ -87,7 +93,11 @@ class Header:
|
||||
inverse = "\n".join(["%s%s"%(' '*4, a) for a in inv_lines])
|
||||
if len(inverse): inverse += '\n'
|
||||
|
||||
supertypes = type.supertypes if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
|
||||
def case_norm(n):
|
||||
n = n.lower()
|
||||
return [k for k in mapping.schema.entities.keys() if k.lower() == n][0]
|
||||
|
||||
supertypes = map(case_norm, type.supertypes) if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
|
||||
superclass = ": %s "%(", ".join(["public %s"%c for c in supertypes]))
|
||||
|
||||
argument_count = mapping.argument_count(type)
|
||||
@@ -95,17 +105,23 @@ class Header:
|
||||
argument_start = argument_count - len(type.attributes)
|
||||
|
||||
argument_name_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return "%s"; '%(i+argument_start, attr.name) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
|
||||
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
|
||||
argument_name_function_body = argument_name_function_body_switch_stmt + argument_name_function_body_tail
|
||||
|
||||
argument_type_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_type(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
|
||||
|
||||
derived = mapping.derived_in_supertype(type)
|
||||
attribute_names = list(map(operator.attrgetter('name'), mapping.arguments(type)))
|
||||
derived_in_supertype = set(derived) & set(attribute_names)
|
||||
derived_in_supertype_indices = sorted(attribute_names.index(nm) for nm in derived_in_supertype)
|
||||
attribute_type_cases = ['case %d: return IfcUtil::Argument_DERIVED; ' % idx for idx in derived_in_supertype_indices]
|
||||
attribute_type_cases += ['case %d: return %s; '%(i+argument_start, mapping.make_argument_type(attr)) for i, attr in enumerate(type.attributes)]
|
||||
argument_type_function_body_switch_stmt = " switch (i) {%s}"%("".join(attribute_type_cases)) if len(type.attributes) else ""
|
||||
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
|
||||
argument_type_function_body = argument_type_function_body_switch_stmt + argument_type_function_body_tail
|
||||
|
||||
argument_entity_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_entity(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
|
||||
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
|
||||
argument_entity_function_body = argument_entity_function_body_switch_stmt + argument_entity_function_body_tail
|
||||
|
||||
@@ -123,10 +139,9 @@ class Header:
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%s.h'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s.h'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
|
||||
@@ -17,15 +17,19 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class Implementation:
|
||||
from schema import OrderedCaseInsensitiveDict
|
||||
|
||||
class Implementation(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
enumeration_functions = []
|
||||
entity_implementations = []
|
||||
schema_entity_statements = []
|
||||
|
||||
schema_name = mapping.schema.name.capitalize()
|
||||
schema_name_upper = mapping.schema.name.upper()
|
||||
|
||||
stringify = lambda s: '"%s"'%s
|
||||
cat = lambda vs: "".join(vs)
|
||||
@@ -43,6 +47,8 @@ class Implementation:
|
||||
templates.enumeration_function,
|
||||
max_id = len(enum.values),
|
||||
name = name,
|
||||
schema_name = schema_name,
|
||||
schema_name_upper = schema_name_upper,
|
||||
values = catc(map(stringify, enum.values)),
|
||||
from_string_statements = catnl(templates.enum_from_string_stmt%dict(context,**locals()) for value in enum.values)
|
||||
)
|
||||
@@ -52,6 +58,7 @@ class Implementation:
|
||||
for name, type in mapping.schema.entities.items():
|
||||
parent_type_test = "" if not type.supertypes or len(type.supertypes) != 1 \
|
||||
else templates.parent_type_test%(type.supertypes[0])
|
||||
|
||||
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
|
||||
constructor_arguments_str = catc("%(full_type)s v%(index)d_%(name)s"%a for a in constructor_arguments if not a['is_derived'])
|
||||
attributes = []
|
||||
@@ -63,6 +70,8 @@ class Implementation:
|
||||
write_attr(
|
||||
templates.const_function,
|
||||
class_name = name,
|
||||
schema_name = schema_name,
|
||||
schema_name_upper = schema_name_upper,
|
||||
name = 'has%s'%arg['name'],
|
||||
arguments = '',
|
||||
return_type = 'bool',
|
||||
@@ -72,10 +81,10 @@ class Implementation:
|
||||
def find_template(arg):
|
||||
simple = mapping.schema.is_simpletype(arg['list_instance_type'])
|
||||
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
|
||||
express = arg['list_instance_type'] in mapping.express_to_cpp_typemapping
|
||||
express = mapping.flatten_type_string(arg['list_instance_type']) in mapping.express_to_cpp_typemapping
|
||||
if arg['is_enum']: return templates.get_attr_stmt_enum
|
||||
elif arg['is_nested']: return templates.get_attr_stmt_nested_array
|
||||
elif arg['is_array'] and not (select or simple or express): return templates.get_attr_stmt_array
|
||||
elif arg['is_nested'] and arg['is_templated_list']: return templates.get_attr_stmt_nested_array
|
||||
elif arg['is_templated_list'] and not (select or simple or express): return templates.get_attr_stmt_array
|
||||
elif arg['non_optional_type'].endswith('*'): return templates.get_attr_stmt_entity
|
||||
else: return templates.get_attr_stmt
|
||||
|
||||
@@ -85,9 +94,11 @@ class Implementation:
|
||||
class_name = name,
|
||||
name = arg['name'],
|
||||
arguments = '',
|
||||
schema_name = schema_name,
|
||||
schema_name_upper = schema_name_upper,
|
||||
return_type = arg['non_optional_type'],
|
||||
body = tmpl % {'index': arg['index']-1,
|
||||
'type' : arg['non_optional_type'].split('::')[0],
|
||||
'type' : arg['non_optional_type'].replace('::Value', ''),
|
||||
'list_instance_type' : arg['list_instance_type']}
|
||||
)
|
||||
|
||||
@@ -96,7 +107,7 @@ class Implementation:
|
||||
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
|
||||
express = arg['list_instance_type'] in mapping.express_to_cpp_typemapping
|
||||
if arg['is_enum']: return templates.set_attr_stmt_enum
|
||||
elif arg['is_array'] and not (select or simple or express): return templates.set_attr_stmt_array
|
||||
elif arg['is_templated_list'] and not (select or simple or express): return templates.set_attr_stmt_array
|
||||
else: return templates.set_attr_stmt
|
||||
|
||||
tmpl = find_template(arg)
|
||||
@@ -106,8 +117,10 @@ class Implementation:
|
||||
name = 'set%s'%arg['name'],
|
||||
arguments = '%s v'%arg['non_optional_type'],
|
||||
return_type = 'void',
|
||||
schema_name = schema_name,
|
||||
schema_name_upper = schema_name_upper,
|
||||
body = tmpl % {'index': arg['index']-1,
|
||||
'type' : arg['non_optional_type'].split('::')[0]}
|
||||
'type' : arg['non_optional_type'].replace('::Value', '')}
|
||||
)
|
||||
|
||||
if arg['is_derived']:
|
||||
@@ -122,7 +135,7 @@ class Implementation:
|
||||
else templates.constructor_stmt
|
||||
impl = tmpl % {'name' : deref_name,
|
||||
'index' : arg['index']-1,
|
||||
'type' : arg['non_optional_type'].split('::')[0]}
|
||||
'type' : arg['non_optional_type'].replace('::Value', '')}
|
||||
if is_optional_non_naked_ptr:
|
||||
impl = templates.constructor_stmt_optional%{'name' : arg_name,
|
||||
'index' : arg['index']-1,
|
||||
@@ -131,17 +144,19 @@ class Implementation:
|
||||
|
||||
def get_attribute_index(entity, attr_name):
|
||||
related_entity = mapping.schema.entities[entity]
|
||||
return [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name)
|
||||
return [a['name'].lower() for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name.lower())
|
||||
|
||||
inverse = [templates.const_function % {
|
||||
'class_name' : name,
|
||||
'schema_name' : schema_name,
|
||||
'schema_name_upper' : schema_name_upper,
|
||||
'name' : i.name,
|
||||
'arguments' : '',
|
||||
'return_type' : '%s::list::ptr' % i.entity,
|
||||
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute)}
|
||||
'return_type' : '::%s::%s::list::ptr' % (schema_name, i.entity),
|
||||
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute), 'schema_name' : schema_name, 'schema_name_upper': schema_name_upper}
|
||||
} for i in (type.inverse.elements if type.inverse else [])]
|
||||
|
||||
superclass = "%s((IfcAbstractEntity*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
|
||||
superclass = "%s((IfcEntityInstanceData*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
|
||||
|
||||
write(
|
||||
templates.entity_implementation,
|
||||
@@ -151,10 +166,12 @@ class Implementation:
|
||||
constructor_implementation = cat(constructor_implementations),
|
||||
attributes = nl(catnl(attributes)),
|
||||
inverse = nl(catnl(inverse)),
|
||||
superclass = superclass
|
||||
superclass = superclass,
|
||||
schema_name = schema_name,
|
||||
schema_name_upper = schema_name_upper
|
||||
)
|
||||
|
||||
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(mapping.schema.types.keys()))
|
||||
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(map(str, mapping.schema.types.keys())))
|
||||
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
|
||||
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.entities.items()]
|
||||
|
||||
@@ -166,12 +183,15 @@ class Implementation:
|
||||
'name' : name,
|
||||
'padding' : ' ' * (max_len - len(name))
|
||||
} for name in enumerable_types]
|
||||
|
||||
enumeration_index_by_str = OrderedCaseInsensitiveDict((j,i) for i,j in enumerate(enumerable_types))
|
||||
def get_parent_id(s):
|
||||
e = mapping.schema.entities.get(s)
|
||||
if e and e.supertypes:
|
||||
return enumeration_index_by_str[e.supertypes[0]]
|
||||
else: return -1
|
||||
|
||||
parent_type_statements = [templates.parent_type_stmt % {
|
||||
'name' : name,
|
||||
'parent' : type.supertypes[0],
|
||||
'padding' : ' ' * (max_len - len(name))
|
||||
} for name, type in mapping.schema.entities.items() if type.supertypes and len(type.supertypes) == 1]
|
||||
parent_type_statements = ",".join(map(str, map(get_parent_id, enumerable_types)))
|
||||
|
||||
max_id = len(enumerable_types)
|
||||
|
||||
@@ -189,44 +209,51 @@ class Implementation:
|
||||
constructor = templates.constructor_single_initlist if superclass \
|
||||
else templates.constructor
|
||||
|
||||
def compose(params):
|
||||
simpletype_impl_cast = templates.simpletype_impl_cast_templated if mapping.is_templated_list(type) \
|
||||
else templates.simpletype_impl_cast
|
||||
|
||||
simpletype_impl_constructor = templates.simpletype_impl_constructor_templated if mapping.is_templated_list(type) \
|
||||
else templates.simpletype_impl_constructor
|
||||
|
||||
def compose(params, schema_name=schema_name, schema_name_upper=schema_name_upper):
|
||||
class_name, attr_type, superclass, superclass_init, name, tmpl, return_type, args, body = params
|
||||
underlying_type = mapping.list_instance_type(type)
|
||||
arguments = ",".join(args)
|
||||
body = body % locals()
|
||||
return tmpl % locals()
|
||||
|
||||
simple_type_impl.append(templates.simpletype_impl_comment % {'name': class_name})
|
||||
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcAbstractEntity*)0")+x, (
|
||||
('getArgumentType', templates.const_function, 'IfcUtil::ArgumentType', ('unsigned int i',), templates.simpletype_impl_argument_type ),
|
||||
('getArgument', templates.const_function, 'Argument*', ('unsigned int i',), templates.simpletype_impl_argument ),
|
||||
('is', templates.const_function, 'bool', ('Type::Enum v',), simpletype_impl_is ),
|
||||
('type', templates.const_function, 'Type::Enum', (), templates.simpletype_impl_type ),
|
||||
('Class', templates.function, 'Type::Enum', (), templates.simpletype_impl_class ),
|
||||
('', constructor, '', ('IfcAbstractEntity* e',), templates.simpletype_impl_explicit_constructor),
|
||||
('', constructor, '', ("%s v" % type_str,), templates.simpletype_impl_constructor ),
|
||||
('', templates.cast_function, type_str, (), templates.simpletype_impl_cast )
|
||||
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcEntityInstanceData*)0")+x, (
|
||||
('Class', templates.function, 'const IfcParse::type_declaration&', (), templates.simpletype_impl_class ),
|
||||
('declaration', templates.const_function, 'const IfcParse::type_declaration&', (), templates.simpletype_impl_declaration ),
|
||||
('', constructor, '', ('IfcEntityInstanceData* e',), templates.simpletype_impl_explicit_constructor),
|
||||
('', constructor, '', ("%s v" % type_str,), simpletype_impl_constructor ),
|
||||
('', templates.cast_function, type_str, (), simpletype_impl_cast )
|
||||
))))
|
||||
simple_type_impl.append('')
|
||||
|
||||
external_definitions = [("extern entity* %s_%%s_type;" % schema_name_upper) % n for n in mapping.schema.entities.keys() ] + \
|
||||
[("extern type_declaration* %s_%%s_type;" % schema_name_upper) % n for n in mapping.schema.simpletypes.keys()]
|
||||
|
||||
self.str = templates.implementation % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
'schema_name' : mapping.schema.name.capitalize(),
|
||||
'schema_name_upper' : schema_name_upper,
|
||||
'schema_name' : schema_name,
|
||||
'max_id' : max_id,
|
||||
'enumeration_functions' : cat(enumeration_functions),
|
||||
'schema_entity_statements' : catnl(schema_entity_statements),
|
||||
'type_name_strings' : type_name_strings,
|
||||
'string_map_statements' : catnl(string_map_statements),
|
||||
'simple_type_statement' : simple_type_statements,
|
||||
'parent_type_statements' : catnl(parent_type_statements),
|
||||
'parent_type_statements' : parent_type_statements,
|
||||
'entity_implementations' : catnl(entity_implementations),
|
||||
'simple_type_impl' : catnl(simple_type_impl)
|
||||
'simple_type_impl' : catnl(simple_type_impl),
|
||||
'external_definitions' : catnl(external_definitions)
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%s.cpp'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s.cpp'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import templates
|
||||
|
||||
class LateBoundImplementation:
|
||||
def __init__(self, mapping):
|
||||
schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
entity_descriptors = []
|
||||
enumeration_descriptors = []
|
||||
derived_field_statements = []
|
||||
inverse_implementations = []
|
||||
|
||||
for name, type in mapping.schema.simpletypes.items():
|
||||
entity_descriptors.append(templates.entity_descriptor % {
|
||||
'type' : name,
|
||||
'parent_statement' : '0',
|
||||
'entity_descriptor_attributes' : templates.entity_descriptor_attribute_without_entity % {
|
||||
'name' : 'wrappedValue',
|
||||
'optional' : 'false',
|
||||
'type' : mapping.make_argument_type(mapping.schema.types[name].type)
|
||||
}
|
||||
})
|
||||
|
||||
emitted_entities = set()
|
||||
entities_to_emit = mapping.schema.entities.keys()
|
||||
while len(emitted_entities) < len(mapping.schema.entities):
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if name in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
|
||||
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
|
||||
entity_descriptor_attributes = []
|
||||
for arg in constructor_arguments:
|
||||
if not arg['is_inherited']:
|
||||
is_enumeration = arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION'
|
||||
tmpl = templates.entity_descriptor_attribute_with_entity
|
||||
entity_name = arg['argument_type'] if is_enumeration else arg['argument_entity'].split('::')[1]
|
||||
entity_descriptor_attributes.append(tmpl % {
|
||||
'name' : arg['name'],
|
||||
'optional' : 'true' if arg['is_optional'] else 'false',
|
||||
'type' : arg['argument_type_enum'],
|
||||
'entity_name': entity_name
|
||||
})
|
||||
|
||||
emitted_entities.add(name)
|
||||
parent_statement = '0' if len(type.supertypes) != 1 else templates.entity_descriptor_parent % {
|
||||
'type' : type.supertypes[0]
|
||||
}
|
||||
entity_descriptors.append(templates.entity_descriptor % {
|
||||
'type' : name,
|
||||
'parent_statement' : parent_statement,
|
||||
'entity_descriptor_attributes' : '\n'.join(entity_descriptor_attributes)
|
||||
})
|
||||
|
||||
for name, enum in mapping.schema.enumerations.items():
|
||||
enumeration_descriptor_values = '\n'.join([templates.enumeration_descriptor_value % {
|
||||
'name' : v
|
||||
} for v in enum.values])
|
||||
enumeration_descriptors.append(templates.enumeration_descriptor % {
|
||||
'type' : name,
|
||||
'enumeration_descriptor_values' : enumeration_descriptor_values
|
||||
})
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
|
||||
statements = ''.join(templates.derived_field_statement_attrs % (a['index']-1) for a in constructor_arguments if a['is_derived'])
|
||||
if len(statements):
|
||||
derived_field_statements.append(templates.derived_field_statement % {
|
||||
'type' : name,
|
||||
'statements' : statements
|
||||
})
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if type.inverse:
|
||||
for attr in type.inverse.elements:
|
||||
related_entity = mapping.schema.entities[attr.entity]
|
||||
related_attrs = [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)]
|
||||
|
||||
inverse_implementations.append(templates.inverse_implementation % {
|
||||
'type' : name,
|
||||
'name' : attr.name,
|
||||
'related_type' : attr.entity,
|
||||
'index' : related_attrs.index(attr.attribute)
|
||||
})
|
||||
|
||||
self.str = templates.lb_implementation % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
'schema_name' : mapping.schema.name.capitalize(),
|
||||
'entity_descriptors' : '\n'.join(entity_descriptors),
|
||||
'enumeration_descriptors' : '\n'.join(enumeration_descriptors),
|
||||
'derived_field_statements' : '\n'.join(derived_field_statements),
|
||||
'inverse_implementations' : '\n'.join(inverse_implementations)
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s-latebound.cpp'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import nodes
|
||||
import templates
|
||||
|
||||
@@ -28,8 +31,15 @@ class Mapping:
|
||||
'integer' : 'int',
|
||||
'real' : 'double',
|
||||
'number' : 'double',
|
||||
'string' : 'std::string'
|
||||
'string' : 'std::string',
|
||||
'binary' : 'boost::dynamic_bitset<>'
|
||||
}
|
||||
|
||||
supported_argument_types = set([
|
||||
'INT', 'BOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE',
|
||||
'AGGREGATE_OF_INT', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE',
|
||||
'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE',
|
||||
])
|
||||
|
||||
def __init__(self, schema):
|
||||
self.schema = schema
|
||||
@@ -44,17 +54,17 @@ class Mapping:
|
||||
def simple_type_parent(self, type):
|
||||
parent = self.schema.types[type].type.type
|
||||
if isinstance(parent, nodes.AggregationType): parent = None
|
||||
return None if parent in self.express_to_cpp_typemapping else parent
|
||||
return None if str(parent) in self.express_to_cpp_typemapping else parent
|
||||
|
||||
def make_type_string(self, type):
|
||||
if isinstance(type, str):
|
||||
return self.express_to_cpp_typemapping.get(type, type)
|
||||
if isinstance(type, (str, nodes.BinaryType, nodes.StringType)):
|
||||
return self.express_to_cpp_typemapping.get(str(type), "::%s::%s" % (self.schema.name.capitalize(), type))
|
||||
else:
|
||||
is_list = self.schema.is_entity(type.type)
|
||||
is_nested_list = isinstance(type.type, nodes.AggregationType)
|
||||
tmpl = templates.list_list_type if is_nested_list else templates.list_type if is_list else templates.array_type
|
||||
return tmpl % {
|
||||
'instance_type' : self.make_type_string(type.type),
|
||||
'instance_type' : self.make_type_string(self.flatten_type_string(type.type)),
|
||||
'lower' : type.bounds.lower,
|
||||
'upper' : type.bounds.upper,
|
||||
}
|
||||
@@ -70,66 +80,71 @@ class Mapping:
|
||||
def make_argument_entity(self, attr):
|
||||
type = attr.type if hasattr(attr, 'type') else attr
|
||||
while isinstance(type, nodes.AggregationType): type = type.type
|
||||
if type in self.express_to_cpp_typemapping or isinstance(type, nodes.BinaryType): return "Type::UNDEFINED"
|
||||
if str(type) in self.express_to_cpp_typemapping: return "Type::UNDEFINED"
|
||||
else: return "Type::%s" % type
|
||||
|
||||
def make_argument_type(self, attr):
|
||||
def _make_argument_type(type):
|
||||
if type in self.express_to_cpp_typemapping:
|
||||
return self.express_to_cpp_typemapping.get(type, type).split('::')[-1].upper()
|
||||
elif self.schema.is_entity(type):
|
||||
return "ENTITY"
|
||||
elif self.schema.is_type(type):
|
||||
return _make_argument_type(self.schema.types[type].type.type)
|
||||
if self.schema.is_entity(type) or isinstance(type, nodes.SelectType):
|
||||
return "ENTITY_INSTANCE"
|
||||
elif isinstance(type, nodes.BinaryType):
|
||||
return "UNKNOWN"
|
||||
return "BINARY"
|
||||
elif isinstance(type, nodes.StringType):
|
||||
return "STRING"
|
||||
elif isinstance(type, nodes.EnumerationType):
|
||||
return "ENUMERATION"
|
||||
elif isinstance(type, nodes.SelectType):
|
||||
return "ENTITY"
|
||||
elif isinstance(type, nodes.AggregationType):
|
||||
ty = _make_argument_type(type.type)
|
||||
if ty == "UNKNOWN": return "UNKNOWN"
|
||||
return "%s_LIST"%ty if ty.startswith("ENTITY") else ("VECTOR_%s"%ty)
|
||||
else: raise ValueError
|
||||
supported = {'INT', 'BOOL', 'DOUBLE', 'STRING', 'VECTOR_INT', 'VECTOR_DOUBLE', 'VECTOR_STRING', 'ENTITY', 'ENTITY_LIST', 'ENTITY_LIST_LIST', 'ENUMERATION'}
|
||||
return "AGGREGATE_OF_" + ty
|
||||
elif str(type) in self.express_to_cpp_typemapping:
|
||||
return self.express_to_cpp_typemapping.get(str(type), type).split('::')[-1].upper()
|
||||
elif self.schema.is_type(type):
|
||||
return _make_argument_type(self.schema.types[type].type.type)
|
||||
else:
|
||||
raise ValueError("Unable to map type %r for attribute %r" % (type, attr))
|
||||
ty = _make_argument_type(attr.type if hasattr(attr, 'type') else attr)
|
||||
if ty not in supported: ty = 'UNKNOWN'
|
||||
if ty not in self.supported_argument_types:
|
||||
print("Attribute %r mapped as 'unknown'" % (attr), file=sys.stderr)
|
||||
ty = 'UNKNOWN'
|
||||
return "IfcUtil::Argument_%s" % ty
|
||||
|
||||
def get_type_dep(self, type):
|
||||
if isinstance(type, str):
|
||||
return self.express_to_cpp_typemapping.get(type, type)
|
||||
return self.express_to_cpp_typemapping.get(str(type), type)
|
||||
else:
|
||||
return self.get_type_dep(type.type)
|
||||
|
||||
def get_parameter_type(self, attr, allow_optional, allow_entities, allow_pointer = True):
|
||||
|
||||
attr_type = self.flatten_type(attr.type)
|
||||
type_str = self.express_to_cpp_typemapping.get(str(attr_type), attr_type)
|
||||
|
||||
is_ptr = False
|
||||
|
||||
if self.schema.is_enumeration(attr_type):
|
||||
type_str = '%s::%s'%(attr_type, attr_type)
|
||||
type_str = '::%s::%s::Value' % (self.schema.name.capitalize(), attr_type)
|
||||
elif isinstance(type_str, nodes.AggregationType):
|
||||
is_nested_list = isinstance(attr_type.type, nodes.AggregationType)
|
||||
ty = self.get_parameter_type(attr_type.type if is_nested_list else attr_type, False, allow_entities, False)
|
||||
if True and self.schema.is_select(attr_type.type):
|
||||
if self.schema.is_select(attr_type.type):
|
||||
type_str = templates.untyped_list
|
||||
elif self.schema.is_simpletype(ty) or ty in self.express_to_cpp_typemapping.values():
|
||||
type_str = templates.array_type % {
|
||||
elif self.schema.is_simpletype(ty) or str(ty) in self.express_to_cpp_typemapping.values():
|
||||
tmpl = templates.nested_array_type if is_nested_list else templates.array_type
|
||||
bounds = (attr_type.bounds.lower, attr_type.bounds.upper) if attr_type.bounds else (-1, -1)
|
||||
type_str = tmpl % {
|
||||
'instance_type' : ty,
|
||||
'lower' : attr_type.bounds.lower,
|
||||
'upper' : attr_type.bounds.upper
|
||||
'lower' : bounds[0],
|
||||
'upper' : bounds[1]
|
||||
}
|
||||
else:
|
||||
tmpl = templates.list_list_type if is_nested_list else templates.list_type
|
||||
type_str = tmpl % {
|
||||
'instance_type': ty
|
||||
}
|
||||
elif allow_pointer and (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
|
||||
type_str += '*'
|
||||
elif (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
|
||||
type_str = '::%s::%s' % (self.schema.name.capitalize(), attr_type)
|
||||
if allow_pointer:
|
||||
type_str += "*"
|
||||
is_ptr = True
|
||||
elif not allow_pointer and self.schema.is_select(type_str):
|
||||
type_str = "IfcUtil::IfcBaseClass*"
|
||||
@@ -151,23 +166,34 @@ class Mapping:
|
||||
return c + ([str(s) for s in t.derive.elements] if t.derive else [])
|
||||
|
||||
def list_instance_type(self, attr):
|
||||
f = lambda v : 'IfcUtil::IfcBaseClass' if self.schema.is_select(v) else v
|
||||
if self.is_array(attr.type):
|
||||
if not isinstance(attr.type, str) and self.is_array(attr.type.type):
|
||||
if isinstance(attr.type.type, str):
|
||||
return f(attr.type.type)
|
||||
else: return f(attr.type.type.type)
|
||||
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
|
||||
if isinstance(attr_type, str): return None
|
||||
def f(v):
|
||||
v = self.flatten_type(v)
|
||||
if self.schema.is_select(v):
|
||||
return 'IfcUtil::IfcBaseClass'
|
||||
elif str(v) in self.schema.types or str(v) in self.schema.entities:
|
||||
return "::%s::%s" % (self.schema.name.capitalize(), v)
|
||||
else: return str(v)
|
||||
if self.is_array(attr_type):
|
||||
if not isinstance(attr_type, str) and self.is_array(attr_type.type):
|
||||
if isinstance(attr_type.type, str):
|
||||
return f(attr_type.type)
|
||||
else: return f(attr_type.type.type)
|
||||
else:
|
||||
if isinstance(attr.type, str):
|
||||
return f(attr.type)
|
||||
else: return f(attr.type.type)
|
||||
if isinstance(attr_type, str):
|
||||
return f(attr_type)
|
||||
else: return f(attr_type.type)
|
||||
return None
|
||||
|
||||
def is_templated_list(self, attr):
|
||||
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
|
||||
if isinstance(attr, str): return False
|
||||
ty = self.list_instance_type(attr)
|
||||
arr = self.is_array(attr.type)
|
||||
if ty is None: return False
|
||||
arr = self.is_array(attr_type)
|
||||
simple = self.schema.is_simpletype(ty)
|
||||
express = ty in self.express_to_cpp_typemapping
|
||||
express = self.flatten_type_string(ty) in self.express_to_cpp_typemapping
|
||||
select = ty == 'IfcUtil::IfcBaseClass'
|
||||
return arr and not simple and not express and not select
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ import string
|
||||
import collections
|
||||
|
||||
class Node:
|
||||
def __init__(self, tokens):
|
||||
self.tokens = tokens
|
||||
def __init__(self, tokens = None):
|
||||
self.tokens = tokens or []
|
||||
self.init()
|
||||
def tokens_of_type(self, cls):
|
||||
return [t for t in self.tokens if isinstance(t, cls)]
|
||||
@@ -44,15 +44,17 @@ class TypeDeclaration(Node):
|
||||
class EntityDeclaration(Node):
|
||||
name = property(lambda self: self.tokens[1])
|
||||
attributes = property(lambda self: self.tokens_of_type(ExplicitAttribute))
|
||||
abstract = property(lambda self: self.single_token_of_type(SuperTypeExpression) is not None and \
|
||||
self.single_token_of_type(SuperTypeExpression).abstract)
|
||||
def init(self):
|
||||
assert self.tokens[0] == 'entity'
|
||||
s = self.single_token_of_type(SubtypeExpression)
|
||||
s = self.single_token_of_type(SubTypeExpression)
|
||||
self.inverse = self.single_token_of_type(AttributeList, 'type', 'inverse')
|
||||
self.derive = self.single_token_of_type(AttributeList, 'type', 'derive')
|
||||
self.supertypes = s.types if s else []
|
||||
def __repr__(self):
|
||||
builder = ""
|
||||
builder += "Entity(%s)" % (self.name)
|
||||
builder += "%sEntity(%s)" % ("Abstract " if self.abstract else "", self.name)
|
||||
if len(self.supertypes):
|
||||
builder += "\n Supertypes: %s"%(",".join(self.supertypes))
|
||||
if len(self.attributes):
|
||||
@@ -106,12 +108,20 @@ class SelectType(Node):
|
||||
class SubSuperTypeExpression(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
types = property(lambda self: self.tokens[3::2])
|
||||
abstract = False
|
||||
def init(self):
|
||||
assert self.type == self.class_type
|
||||
if self.tokens[0] == 'abstract':
|
||||
self.tokens = self.tokens[1:]
|
||||
self.abstract = True
|
||||
assert self.type == self.type_relationship
|
||||
|
||||
|
||||
class SubtypeExpression(SubSuperTypeExpression):
|
||||
class_type = 'subtype'
|
||||
class SubTypeExpression(SubSuperTypeExpression):
|
||||
type_relationship = 'subtype'
|
||||
|
||||
|
||||
class SuperTypeExpression(SubSuperTypeExpression):
|
||||
type_relationship = 'supertype'
|
||||
|
||||
|
||||
class AttributeList(Node):
|
||||
@@ -127,8 +137,8 @@ class AttributeList(Node):
|
||||
|
||||
class InverseAttribute(Node):
|
||||
name = property(lambda self: self.tokens[0])
|
||||
type = property(lambda self: self.tokens[2])
|
||||
bounds = property(lambda self: None if len(self.tokens) == 6 else self.tokens[3])
|
||||
type = property(lambda self: self.tokens[2] if self.tokens[2] != self.tokens[-4] else None)
|
||||
bounds = property(lambda self: None if len(self.tokens) != 9 else self.tokens[3])
|
||||
entity = property(lambda self: self.tokens[-4])
|
||||
attribute = property(lambda self: self.tokens[-2])
|
||||
def init(self):
|
||||
@@ -149,7 +159,7 @@ class BinaryType(Node):
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "BINARY"
|
||||
return "binary"
|
||||
|
||||
|
||||
class BoundSpecification(Node):
|
||||
@@ -170,6 +180,23 @@ class ExplicitAttribute(Node):
|
||||
def init(self):
|
||||
# NB: This assumes a single name per attribute
|
||||
# definition, which is not necessarily the case.
|
||||
if self.tokens[0] == "self":
|
||||
i = list(self.tokens).index(":")
|
||||
self.tokens = self.tokens[i-1:]
|
||||
assert self.tokens[1] == ':'
|
||||
def __repr__(self):
|
||||
return "%s : %s%s" % (self.name, self.type, " ?" if self.optional else "")
|
||||
|
||||
|
||||
class WidthSpec(Node):
|
||||
def init(self):
|
||||
if self.tokens[-1] == "fixed":
|
||||
self.tokens[-1:] = []
|
||||
assert (self.tokens[0], self.tokens[-1]) == ("(", ")")
|
||||
self.width = int("".join(self.tokens[1:-1]))
|
||||
|
||||
class StringType(Node):
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "string"
|
||||
|
||||
@@ -18,29 +18,67 @@
|
||||
###############################################################################
|
||||
|
||||
import nodes
|
||||
import platform
|
||||
import collections
|
||||
|
||||
if tuple(map(int, platform.python_version_tuple())) < (2, 7):
|
||||
import ordereddict
|
||||
collections.OrderedDict = ordereddict.OrderedDict
|
||||
|
||||
# According to ISO 10303-11 7.1.2: Letters: "... The case of
|
||||
# letters is significant only within explicit string literals."
|
||||
class OrderedCaseInsensitiveDict_KeyObject(str):
|
||||
def __eq__(self, other):
|
||||
return self.lower() == other.lower()
|
||||
def __hash__(self):
|
||||
return hash(self.lower())
|
||||
|
||||
|
||||
class OrderedCaseInsensitiveDict(collections.OrderedDict):
|
||||
def __init__(self, *args, **kwargs):
|
||||
collections.OrderedDict.__init__(self)
|
||||
for key, value in collections.OrderedDict(*args, **kwargs).items():
|
||||
self[OrderedCaseInsensitiveDict_KeyObject(key)] = value
|
||||
def __setitem__(self, key, value):
|
||||
return collections.OrderedDict.__setitem__(self, OrderedCaseInsensitiveDict_KeyObject(key), value)
|
||||
def __getitem__(self, key):
|
||||
return collections.OrderedDict.__getitem__(self, OrderedCaseInsensitiveDict_KeyObject(key))
|
||||
def get(self, key, *args, **kwargs):
|
||||
return collections.OrderedDict.get(self, OrderedCaseInsensitiveDict_KeyObject(key), *args, **kwargs)
|
||||
def __contains__(self, key):
|
||||
return collections.OrderedDict.__contains__(self, OrderedCaseInsensitiveDict_KeyObject(key))
|
||||
|
||||
|
||||
class Schema:
|
||||
def is_enumeration(self, v):
|
||||
return v in self.enumerations
|
||||
return str(v) in self.enumerations
|
||||
def is_select(self, v):
|
||||
return v in self.selects
|
||||
return str(v) in self.selects
|
||||
def is_simpletype(self, v):
|
||||
return v in self.simpletypes
|
||||
return str(v) in self.simpletypes
|
||||
def is_type(self, v):
|
||||
return v in self.types
|
||||
return str(v) in self.types
|
||||
def is_entity(self, v):
|
||||
return v in self.entities
|
||||
return str(v) in self.entities
|
||||
def __len__(self):
|
||||
return len(self.types) + len(self.entities)
|
||||
def __iter__(self):
|
||||
return iter(self.keys)
|
||||
def __getitem__(self, key):
|
||||
return self.types_entities[key]
|
||||
def __init__(self, parsetree):
|
||||
self.name = parsetree[1]
|
||||
|
||||
sort = lambda d: collections.OrderedDict(sorted(d.items()))
|
||||
sort = lambda d: OrderedCaseInsensitiveDict(sorted(d))
|
||||
|
||||
self.types = sort({t.name:t for t in parsetree if isinstance(t, nodes.TypeDeclaration)})
|
||||
self.entities = sort({t.name:t for t in parsetree if isinstance(t, nodes.EntityDeclaration)})
|
||||
self.types = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.TypeDeclaration)])
|
||||
self.entities = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.EntityDeclaration)])
|
||||
|
||||
self.keys = list(self.types.keys()) + list(self.entities.keys())
|
||||
self.types_entities = {k: v for d in (self.types, self.entities) for k, v in d.items()}
|
||||
|
||||
of_type = lambda *types: sort({a: b.type.type for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)})
|
||||
of_type = lambda *types: sort([(a, b.type.type) for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)])
|
||||
|
||||
self.enumerations = of_type(nodes.EnumerationType)
|
||||
self.selects = of_type(nodes.SelectType)
|
||||
self.simpletypes = of_type(str, nodes.AggregationType)
|
||||
self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType, nodes.StringType)
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import operator
|
||||
|
||||
import nodes
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
class SchemaClass(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
|
||||
class UnmetDependenciesException(Exception): pass
|
||||
|
||||
schema_name = mapping.schema.name
|
||||
self.schema_name = schema_name_title = schema_name.capitalize()
|
||||
|
||||
declared_types = []
|
||||
|
||||
def get_declared_type(type, emitted_names=None):
|
||||
if isinstance(type, nodes.AggregationType):
|
||||
aggr_type = type.aggregate_type
|
||||
make_bound = lambda b: -1 if b == '?' else int(b)
|
||||
bound1, bound2 = map(make_bound, (type.bounds.lower, type.bounds.upper))
|
||||
decl_type = get_declared_type(type.type, emitted_names)
|
||||
return "new aggregation_type(aggregation_type::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(decl_type)s)" % locals()
|
||||
elif isinstance(type, nodes.BinaryType):
|
||||
return "new simple_type(simple_type::binary_type)"
|
||||
elif isinstance(type, nodes.StringType):
|
||||
return "new simple_type(simple_type::string_type)"
|
||||
elif isinstance(type, str):
|
||||
if mapping.schema.is_type(type) or mapping.schema.is_entity(type):
|
||||
if emitted_names is None or type.lower() in emitted_names:
|
||||
return "new named_type(%s_%s_type)" % (schema_name, type)
|
||||
else:
|
||||
raise UnmetDependenciesException(type)
|
||||
else:
|
||||
return "new simple_type(simple_type::%s_type)" % type
|
||||
|
||||
def find_inverse_name_and_index(entity_name, attribute_name):
|
||||
attributes_per_subtype = []
|
||||
while True:
|
||||
entity = mapping.schema.entities[entity_name]
|
||||
attr_names = list(map(operator.attrgetter('name'), entity.attributes))
|
||||
if len(attr_names):
|
||||
attributes_per_subtype.append((entity_name, attr_names))
|
||||
if len(entity.supertypes) != 1: break
|
||||
entity_name = entity.supertypes[0]
|
||||
index = 0
|
||||
for et, attrs in attributes_per_subtype[::-1]:
|
||||
try: return et, attrs.index(attribute_name)
|
||||
except: pass
|
||||
|
||||
else:
|
||||
raise Exception("No declared type for <%r>" % type)
|
||||
|
||||
statements = ['',
|
||||
'#include "../ifcparse/IfcSchema.h"',
|
||||
'#include "../ifcparse/%(schema_name_title)s.h"' % locals(),
|
||||
'',
|
||||
'using namespace IfcParse;',
|
||||
'']
|
||||
|
||||
collections_by_type = (('entity', mapping.schema.entities ),
|
||||
('type_declaration', mapping.schema.simpletypes ),
|
||||
('select_type', mapping.schema.selects ),
|
||||
('enumeration_type', mapping.schema.enumerations))
|
||||
|
||||
for cpp_type, collection in collections_by_type:
|
||||
for name in collection.keys():
|
||||
statements.append('%(cpp_type)s* %(schema_name)s_%(name)s_type = 0;' % locals())
|
||||
|
||||
declarations_by_index = []
|
||||
|
||||
statements.append("{factory_placeholder}")
|
||||
|
||||
statements.append("""
|
||||
#if defined(__clang__)
|
||||
__attribute__((optnone))
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
""")
|
||||
statements.append('IfcParse::schema_definition* %(schema_name)s_populate_schema() {' % locals())
|
||||
|
||||
emitted = set()
|
||||
len_to_emit = len(mapping.schema)
|
||||
|
||||
def write_simpletype(schema_name, name, type):
|
||||
try:
|
||||
declared_type = get_declared_type(type, emitted)
|
||||
except UnmetDependenciesException:
|
||||
# @todo?
|
||||
# print("Unmet", repr(name))
|
||||
return False
|
||||
|
||||
statements.append(' %(schema_name)s_%(name)s_type = new type_declaration("%(name)s", %%(index_in_schema_%(name)s)d, %(declared_type)s);' % locals())
|
||||
|
||||
def write_enumeration(schema_name, name, enum):
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<std::string> items; items.reserve(%d);' % len(enum.values))
|
||||
statements.extend(map(lambda v: ' items.push_back("%s");' % v, sorted(enum.values)))
|
||||
statements.append(' %(schema_name)s_%(name)s_type = new enumeration_type("%(name)s", %%(index_in_schema_%(name)s)d, items);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
def write_entity(schema_name, name, type):
|
||||
if len(type.supertypes) == 0 or set(map(lambda s: s.lower(), type.supertypes)) < emitted:
|
||||
supertype = '0' if len(type.supertypes) == 0 else '%s_%s_type' % (schema_name, type.supertypes[0])
|
||||
is_abstract = "true" if type.abstract else "false"
|
||||
statements.append(' %(schema_name)s_%(name)s_type = new entity("%(name)s", %(is_abstract)s, %%(index_in_schema_%(name)s)d, %(supertype)s);' % locals())
|
||||
else: return False
|
||||
|
||||
def write_select(schema_name, name, type):
|
||||
if set(map(lambda s: s.lower(),type.values)) < emitted:
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const declaration*> items; items.reserve(%d);' % len(type.values))
|
||||
statements.extend(map(lambda v: ' items.push_back(%s_%s_type);' % (schema_name, v), sorted(type.values)))
|
||||
statements.append(' %(schema_name)s_%(name)s_type = new select_type("%(name)s", %%(index_in_schema_%(name)s)d, items);' % locals())
|
||||
statements.append(' }')
|
||||
else: return False
|
||||
|
||||
def write(name):
|
||||
if mapping.schema.is_simpletype(name):
|
||||
fn = write_simpletype
|
||||
elif mapping.schema.is_enumeration(name):
|
||||
fn = write_enumeration
|
||||
elif mapping.schema.is_entity(name):
|
||||
fn = write_entity
|
||||
elif mapping.schema.is_select(name):
|
||||
fn = write_select
|
||||
|
||||
decl = mapping.schema[name]
|
||||
if isinstance(decl, nodes.TypeDeclaration):
|
||||
decl = decl.type.type
|
||||
return fn(schema_name, name, decl) is not False
|
||||
|
||||
while len(emitted) < len_to_emit:
|
||||
for name in mapping.schema:
|
||||
if name.lower() in emitted: continue
|
||||
if write(name):
|
||||
emitted.add(name.lower())
|
||||
declarations_by_index.append(name)
|
||||
declared_types.append('%(schema_name)s_%(name)s_type' % locals())
|
||||
|
||||
num_declarations = len(declared_types)
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
derived = set(mapping.derived_in_supertype(type))
|
||||
attribute_names = list(map(operator.attrgetter('name'), mapping.arguments(type)))
|
||||
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const attribute*> attributes; attributes.reserve(%d);' % len(type.attributes))
|
||||
for attr in type.attributes:
|
||||
attr_name, optional = attr.name, str(attr.optional).lower()
|
||||
decl_type = get_declared_type(attr.type)
|
||||
statements.append(' attributes.push_back(new attribute("%(attr_name)s", %(decl_type)s, %(optional)s));' % locals())
|
||||
statements.append(' std::vector<bool> derived; derived.reserve(%d);' % len(attribute_names))
|
||||
statements.append(' ' + " ".join(map(lambda b: 'derived.push_back(%s);' % str(b in derived).lower(), attribute_names)))
|
||||
statements.append(' %(schema_name)s_%(name)s_type->set_attributes(attributes, derived);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if type.inverse:
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const inverse_attribute*> attributes; attributes.reserve(%d);' % len(type.inverse.elements))
|
||||
for attr in type.inverse.elements:
|
||||
if attr.bounds:
|
||||
make_bound = lambda b: -1 if b == '?' else int(b)
|
||||
bound1, bound2 = map(make_bound, (attr.bounds.lower, attr.bounds.upper))
|
||||
else:
|
||||
bound1, bound2 = -1, -1
|
||||
attr_name, aggr_type, entity_ref = attr.name, attr.type, attr.entity
|
||||
if aggr_type is None: aggr_type = 'unspecified'
|
||||
attribute_entity, attribute_entity_index = find_inverse_name_and_index(entity_ref, attr.attribute)
|
||||
statements.append(' attributes.push_back(new inverse_attribute("%(attr_name)s", inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(schema_name)s_%(entity_ref)s_type, %(schema_name)s_%(attribute_entity)s_type->attributes()[%(attribute_entity_index)d]));' % locals())
|
||||
statements.append(' %(schema_name)s_%(name)s_type->set_inverse_attributes(attributes);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
subtypes = defaultdict(list)
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
for ty in type.supertypes:
|
||||
subtypes[ty].append(name)
|
||||
|
||||
for name, tys in subtypes.items():
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const entity*> defs; defs.reserve(%d);' % len(tys))
|
||||
statements.append((' ' + "".join(map(lambda t: ("defs.push_back(%%(schema_name)s_%s_type);" % t), tys))) % locals())
|
||||
statements.append(' %(schema_name)s_%(name)s_type->set_subtypes(defs);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
statements.append('')
|
||||
statements.append(' std::vector<const declaration*> declarations; declarations.reserve(%(num_declarations)d);' % locals())
|
||||
for type_name in declared_types:
|
||||
statements.append(' declarations.push_back(%(type_name)s);' % locals())
|
||||
|
||||
statements.append(' return new schema_definition("%(schema_name)s", declarations, new %(schema_name)s_instance_factory());' % locals())
|
||||
|
||||
statements.extend(('}',''))
|
||||
|
||||
statements.append("""
|
||||
#if defined(__clang__)
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC pop_options
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
""")
|
||||
|
||||
statements.extend(('const schema_definition& %s::get_schema() {' % schema_name_title,
|
||||
'',
|
||||
' static const schema_definition* s = %(schema_name)s_populate_schema();' % locals(),
|
||||
' return *s;',
|
||||
'}','',''))
|
||||
|
||||
declarations_by_index.sort(key=str.lower)
|
||||
declarations_by_index_map = dict(("index_in_schema_%s" % j,i) for i,j in enumerate(declarations_by_index))
|
||||
|
||||
def bind(s):
|
||||
if "%" in s: return s % declarations_by_index_map
|
||||
else: return s
|
||||
|
||||
can_be_instantiated_set = set(list(mapping.schema.entities.keys()) + list(mapping.schema.simpletypes.keys()))
|
||||
def can_be_instantiated(idx_name):
|
||||
name = idx_name[1]
|
||||
return name in can_be_instantiated_set
|
||||
|
||||
instance_mapping = """switch(data->type()->index_in_schema()) {
|
||||
%s
|
||||
default: throw IfcParse::IfcException(data->type()->name() + " cannot be instantiated");
|
||||
}
|
||||
""" % "\n ".join(map(lambda tup: ("case %%d: return new ::%s::%%s(data);" % schema_name_title) % tup, filter(can_be_instantiated, enumerate(declarations_by_index))))
|
||||
|
||||
statements[statements.index("{factory_placeholder}")] = """
|
||||
class %(schema_name)s_instance_factory : public IfcParse::instance_factory {
|
||||
virtual IfcUtil::IfcBaseClass* operator()(IfcEntityInstanceData* data) const {
|
||||
%(instance_mapping)s
|
||||
}
|
||||
};
|
||||
""" % locals()
|
||||
|
||||
self.str = "\n".join(map(bind, statements))
|
||||
|
||||
self.file_name = '%s-schema.cpp'%self.schema_name
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
@@ -23,19 +23,24 @@ header = """
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/ifc_parse_api.h"
|
||||
|
||||
#include "../ifcparse/IfcEntityList.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcSchema.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/Argument.h"
|
||||
|
||||
#include "../ifcparse/%(schema_name)senum.h"
|
||||
|
||||
#define IfcSchema %(schema_name)s
|
||||
struct %(schema_name)s {
|
||||
|
||||
namespace %(schema_name)s {
|
||||
static const IfcParse::schema_definition& get_schema();
|
||||
|
||||
const char* const Identifier = "%(schema_name_upper)s";
|
||||
static const char* const Identifier;
|
||||
|
||||
// Forward definitions
|
||||
%(forward_definitions)s
|
||||
@@ -43,9 +48,7 @@ const char* const Identifier = "%(schema_name_upper)s";
|
||||
%(declarations)s
|
||||
|
||||
%(class_definitions)s
|
||||
void InitStringMap();
|
||||
IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
"""
|
||||
@@ -54,97 +57,31 @@ enum_header = """
|
||||
#ifndef %(schema_name_upper)sENUM_H
|
||||
#define %(schema_name_upper)sENUM_H
|
||||
|
||||
#define IfcSchema %(schema_name)s
|
||||
#include "../ifcparse/ifc_parse_api.h"
|
||||
|
||||
namespace %(schema_name)s {
|
||||
|
||||
namespace Type {
|
||||
typedef enum {
|
||||
%(types)s, UNDEFINED
|
||||
} Enum;
|
||||
Enum Parent(Enum v);
|
||||
Enum FromString(const std::string& s);
|
||||
std::string ToString(Enum v);
|
||||
bool IsSimple(Enum v);
|
||||
}
|
||||
|
||||
}
|
||||
#include <string>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#endif
|
||||
"""
|
||||
|
||||
lb_header = """
|
||||
#ifndef %(schema_name_upper)sRT_H
|
||||
#define %(schema_name_upper)sRT_H
|
||||
|
||||
#define IfcSchema %(schema_name)s
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcEntityDescriptor.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
|
||||
namespace %(schema_name)s {
|
||||
namespace Type {
|
||||
int GetAttributeCount(Enum t);
|
||||
int GetAttributeIndex(Enum t, const std::string& a);
|
||||
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
|
||||
Enum GetAttributeEntity(Enum t, unsigned char a);
|
||||
const std::string& GetAttributeName(Enum t, unsigned char a);
|
||||
bool GetAttributeOptional(Enum t, unsigned char a);
|
||||
bool GetAttributeDerived(Enum t, unsigned char a);
|
||||
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
|
||||
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
|
||||
std::set<std::string> GetInverseAttributeNames(Enum t);
|
||||
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
|
||||
}}
|
||||
|
||||
#endif
|
||||
"""
|
||||
lb_header = """"""
|
||||
|
||||
implementation= """
|
||||
#include "../ifcparse/%(schema_name)s.h"
|
||||
#include "../ifcparse/IfcSchema.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
|
||||
using namespace %(schema_name)s;
|
||||
#include <map>
|
||||
|
||||
const char* const %(schema_name)s::Identifier = "%(schema_name_upper)s";
|
||||
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
|
||||
IfcUtil::IfcBaseClass* %(schema_name)s::SchemaEntity(IfcAbstractEntity* e) {
|
||||
switch(e->type()) {
|
||||
%(schema_entity_statements)s
|
||||
default: throw IfcException("Unable to find find keyword in schema"); break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Type::ToString(Enum v) {
|
||||
if (v < 0 || v >= %(max_id)d) throw IfcException("Unable to find find keyword in schema");
|
||||
const char* names[] = { %(type_name_strings)s };
|
||||
return names[v];
|
||||
}
|
||||
|
||||
static std::map<std::string,Type::Enum> string_map;
|
||||
void %(schema_name)s::InitStringMap() {
|
||||
%(string_map_statements)s
|
||||
}
|
||||
|
||||
Type::Enum Type::FromString(const std::string& s) {
|
||||
if (string_map.empty()) InitStringMap();
|
||||
std::map<std::string,Type::Enum>::const_iterator it = string_map.find(s);
|
||||
if ( it == string_map.end() ) throw IfcException("Unable to find find keyword in schema");
|
||||
else return it->second;
|
||||
}
|
||||
|
||||
Type::Enum Type::Parent(Enum v){
|
||||
if (v < 0 || v >= %(max_id)d) return (Enum)-1;
|
||||
%(parent_type_statements)s
|
||||
return (Enum)-1;
|
||||
}
|
||||
|
||||
bool Type::IsSimple(Enum v) {
|
||||
return %(simple_type_statement)s;
|
||||
}
|
||||
// External definitions
|
||||
%(external_definitions)s
|
||||
|
||||
%(enumeration_functions)s
|
||||
|
||||
@@ -153,150 +90,7 @@ bool Type::IsSimple(Enum v) {
|
||||
%(entity_implementations)s
|
||||
"""
|
||||
|
||||
lb_implementation = """
|
||||
#include <set>
|
||||
|
||||
#include "../ifcparse/%(schema_name)s.h"
|
||||
#include "../ifcparse/%(schema_name)s-latebound.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcEntityDescriptor.h"
|
||||
|
||||
using namespace %(schema_name)s;
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
using namespace IfcUtil;
|
||||
|
||||
typedef std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map_t;
|
||||
typedef std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map_t;
|
||||
typedef std::map<Type::Enum, std::map<std::string, std::pair<Type::Enum, int> > > inverse_map_t;
|
||||
typedef std::map<Type::Enum,std::set<int> > derived_map_t;
|
||||
|
||||
entity_descriptor_map_t entity_descriptor_map;
|
||||
enumeration_descriptor_map_t enumeration_descriptor_map;
|
||||
inverse_map_t inverse_map;
|
||||
derived_map_t derived_map;
|
||||
|
||||
void InitDescriptorMap() {
|
||||
IfcEntityDescriptor* current;
|
||||
%(entity_descriptors)s
|
||||
// Enumerations
|
||||
IfcEnumerationDescriptor* current_enum;
|
||||
std::vector<std::string> values;
|
||||
%(enumeration_descriptors)s
|
||||
}
|
||||
|
||||
void InitInverseMap() {
|
||||
%(inverse_implementations)s
|
||||
}
|
||||
|
||||
void InitDerivedMap() {
|
||||
%(derived_field_statements)s
|
||||
}
|
||||
|
||||
int Type::GetAttributeIndex(Enum t, const std::string& a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentIndex(a);
|
||||
}
|
||||
|
||||
int Type::GetAttributeCount(Enum t) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentCount();
|
||||
}
|
||||
|
||||
ArgumentType Type::GetAttributeType(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentType(a);
|
||||
}
|
||||
|
||||
Type::Enum Type::GetAttributeEntity(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentEntity(a);
|
||||
}
|
||||
|
||||
const std::string& Type::GetAttributeName(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentName(a);
|
||||
}
|
||||
|
||||
bool Type::GetAttributeOptional(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentOptional(a);
|
||||
}
|
||||
|
||||
bool Type::GetAttributeDerived(Enum t, unsigned char a) {
|
||||
if (derived_map.empty()) ::InitDerivedMap();
|
||||
std::map<Type::Enum,std::set<int> >::const_iterator i = derived_map.find(t);
|
||||
return i != derived_map.end() && i->second.find(a) != i->second.end();
|
||||
}
|
||||
|
||||
std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string& a) {
|
||||
if (enumeration_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEnumerationDescriptor*>::const_iterator i = enumeration_descriptor_map.find(t);
|
||||
if ( i == enumeration_descriptor_map.end() ) throw IfcException("Value not found");
|
||||
else return i->second->getIndex(a);
|
||||
}
|
||||
|
||||
std::pair<Type::Enum, unsigned> Type::GetInverseAttribute(Enum t, const std::string& a) {
|
||||
if (inverse_map.empty()) ::InitInverseMap();
|
||||
inverse_map_t::const_iterator it;
|
||||
inverse_map_t::mapped_type::const_iterator jt;
|
||||
while (true) {
|
||||
it = inverse_map.find(t);
|
||||
if (it != inverse_map.end()) {
|
||||
jt = it->second.find(a);
|
||||
if (jt != it->second.end()) {
|
||||
return jt->second;
|
||||
}
|
||||
}
|
||||
if ((t = Parent(t)) == -1) break;
|
||||
}
|
||||
throw IfcException("Attribute not found");
|
||||
}
|
||||
|
||||
std::set<std::string> Type::GetInverseAttributeNames(Enum t) {
|
||||
if (inverse_map.empty()) ::InitInverseMap();
|
||||
inverse_map_t::const_iterator it;
|
||||
inverse_map_t::mapped_type::const_iterator jt;
|
||||
|
||||
std::set<std::string> return_value;
|
||||
|
||||
while (true) {
|
||||
it = inverse_map.find(t);
|
||||
if (it != inverse_map.end()) {
|
||||
for (jt = it->second.begin(); jt != it->second.end(); ++jt) {
|
||||
return_value.insert(jt->first);
|
||||
}
|
||||
}
|
||||
if ((t = Parent(t)) == -1) break;
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
|
||||
std::map<Type::Enum, std::set<int> >::const_iterator i = derived_map.find(e->type());
|
||||
if (i != derived_map.end()) {
|
||||
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
|
||||
e->setArgumentDerived(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
lb_implementation = """"""
|
||||
|
||||
entity_descriptor = """ current = entity_descriptor_map[Type::%(type)s] = new IfcEntityDescriptor(Type::%(type)s,%(parent_statement)s);
|
||||
%(entity_descriptor_attributes)s"""
|
||||
@@ -307,7 +101,7 @@ entity_descriptor_attribute_with_entity = ' current->add("%(name)s",%(optiona
|
||||
|
||||
enumeration_descriptor = """ values.clear(); values.reserve(128);
|
||||
%(enumeration_descriptor_values)s
|
||||
current_enum = enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
|
||||
enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
|
||||
|
||||
enumeration_descriptor_value = ' values.push_back("%(name)s");'
|
||||
|
||||
@@ -315,89 +109,85 @@ derived_field_statement = ' {std::set<int> idxs; %(statements)sderived_map[Ty
|
||||
derived_field_statement_attrs = 'idxs.insert(%d); '
|
||||
|
||||
simpletype = """%(documentation)s
|
||||
class %(name)s : public %(superclass)s {
|
||||
class IFC_PARSE_API %(name)s : public %(superclass)s {
|
||||
public:
|
||||
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const;
|
||||
virtual Argument* getArgument(unsigned int i) const;
|
||||
bool is(Type::Enum v) const;
|
||||
Type::Enum type() const;
|
||||
static Type::Enum Class();
|
||||
explicit %(name)s (IfcAbstractEntity* e);
|
||||
virtual const IfcParse::type_declaration& declaration() const;
|
||||
static const IfcParse::type_declaration& Class();
|
||||
explicit %(name)s (IfcEntityInstanceData* e);
|
||||
%(name)s (%(type)s v);
|
||||
operator %(type)s() const;
|
||||
};
|
||||
"""
|
||||
|
||||
simpletype_impl_comment = "// Function implementations for %(name)s"
|
||||
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcException(\"argument out of range\"); }"
|
||||
simpletype_impl_argument = "return entity->getArgument(i);"
|
||||
simpletype_impl_is_with_supertype = "return v == Type::%(class_name)s || %(superclass)s::is(v);"
|
||||
simpletype_impl_is_without_supertype = "return v == %(class_name)s::Class();"
|
||||
simpletype_impl_type = "return Type::%(class_name)s;"
|
||||
simpletype_impl_class = "return Type::%(class_name)s;"
|
||||
simpletype_impl_explicit_constructor = "entity = e;"
|
||||
simpletype_impl_constructor = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v); entity = e;"
|
||||
simpletype_impl_cast = "return *entity->getArgument(0);"
|
||||
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcAttributeOutOfRangeException(\"Argument index out of range\"); }"
|
||||
simpletype_impl_argument = "return data_->getArgument(i);"
|
||||
simpletype_impl_is_with_supertype = "return v == %(class_name)s_type || %(superclass)s::is(v);"
|
||||
simpletype_impl_is_without_supertype = "return v == %(class_name)s_type;"
|
||||
simpletype_impl_type = "return *%(schema_name_upper)s_%(class_name)s_type;"
|
||||
simpletype_impl_class = "return *%(schema_name_upper)s_%(class_name)s_type;"
|
||||
simpletype_impl_explicit_constructor = "data_ = e;"
|
||||
simpletype_impl_constructor = "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(class_name)s_type); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v" +"); data_->setArgument(0, attr);}"
|
||||
simpletype_impl_constructor_templated = "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(class_name)s_type); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v->generalize()); data_->setArgument(0, attr);}"
|
||||
simpletype_impl_cast = "return *data_->getArgument(0);"
|
||||
simpletype_impl_cast_templated = "IfcEntityList::ptr es = *data_->getArgument(0); return es->as< %(underlying_type)s >();"
|
||||
simpletype_impl_declaration = "return *%(schema_name_upper)s_%(class_name)s_type;"
|
||||
|
||||
select = """%(documentation)s
|
||||
typedef IfcUtil::IfcBaseClass %(name)s;
|
||||
"""
|
||||
|
||||
enumeration = """namespace %(name)s {
|
||||
enumeration = """struct %(name)s {
|
||||
%(documentation)s
|
||||
typedef enum {%(values)s} %(name)s;
|
||||
const char* ToString(%(name)s v);
|
||||
%(name)s FromString(const std::string& s);
|
||||
}
|
||||
typedef enum {%(values)s} Value;
|
||||
IFC_PARSE_API static const char* ToString(Value v);
|
||||
IFC_PARSE_API static Value FromString(const std::string& s);
|
||||
};
|
||||
"""
|
||||
|
||||
entity = """%(documentation)s
|
||||
class %(name)s %(superclass)s{
|
||||
class IFC_PARSE_API %(name)s %(superclass)s{
|
||||
public:
|
||||
%(attributes)s virtual unsigned int getArgumentCount() const { return %(argument_count)d; }
|
||||
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const {%(argument_type_function_body)s}
|
||||
virtual Type::Enum getArgumentEntity(unsigned int i) const {%(argument_entity_function_body)s}
|
||||
virtual const char* getArgumentName(unsigned int i) const {%(argument_name_function_body)s}
|
||||
virtual Argument* getArgument(unsigned int i) const { return entity->getArgument(i); }
|
||||
%(inverse)s bool is(Type::Enum v) const;
|
||||
Type::Enum type() const;
|
||||
static Type::Enum Class();
|
||||
%(name)s (IfcAbstractEntity* e);
|
||||
%(attributes)s %(inverse)s virtual const IfcParse::entity& declaration() const;
|
||||
static const IfcParse::entity& Class();
|
||||
%(name)s (IfcEntityInstanceData* e);
|
||||
%(name)s (%(constructor_arguments)s);
|
||||
typedef IfcTemplatedEntityList< %(name)s > list;
|
||||
};
|
||||
"""
|
||||
|
||||
enumeration_function="""
|
||||
const char* %(name)s::ToString(%(name)s v) {
|
||||
const char* %(schema_name)s::%(name)s::ToString(Value v) {
|
||||
if ( v < 0 || v >= %(max_id)d ) throw IfcException("Unable to find find keyword in schema");
|
||||
const char* names[] = { %(values)s };
|
||||
return names[v];
|
||||
}
|
||||
|
||||
%(name)s::%(name)s %(name)s::FromString(const std::string& s) {
|
||||
%(schema_name)s::%(name)s::Value %(schema_name)s::%(name)s::FromString(const std::string& s) {
|
||||
%(from_string_statements)s
|
||||
throw IfcException("Unable to find find keyword in schema");
|
||||
}
|
||||
"""
|
||||
|
||||
entity_implementation = """// Function implementations for %(name)s
|
||||
%(attributes)s%(inverse)sbool %(name)s::is(Type::Enum v) const { return v == Type::%(name)s%(parent_type_test)s; }
|
||||
Type::Enum %(name)s::type() const { return Type::%(name)s; }
|
||||
Type::Enum %(name)s::Class() { return Type::%(name)s; }
|
||||
%(name)s::%(name)s(IfcAbstractEntity* e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); entity = e; }
|
||||
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s entity = e; EntityBuffer::Add(this); }
|
||||
%(attributes)s
|
||||
%(inverse)s
|
||||
const IfcParse::entity& %(schema_name)s::%(name)s::declaration() const { return *%(schema_name_upper)s_%(name)s_type; }
|
||||
const IfcParse::entity& %(schema_name)s::%(name)s::Class() { return *%(schema_name_upper)s_%(name)s_type; }
|
||||
%(schema_name)s::%(name)s::%(name)s(IfcEntityInstanceData* e) : %(superclass)s { if (!e) return; if (e->type() != %(schema_name_upper)s_%(name)s_type) throw IfcException("Unable to find find keyword in schema"); data_ = e; }
|
||||
%(schema_name)s::%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s {data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(name)s_type); %(constructor_implementation)s }
|
||||
"""
|
||||
|
||||
optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s"
|
||||
|
||||
function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
|
||||
const_function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
|
||||
constructor = "%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
|
||||
constructor_single_initlist = "%(class_name)s::%(class_name)s(%(arguments)s) : %(superclass)s(%(superclass_init)s) { %(body)s }"
|
||||
cast_function = "%(class_name)s::operator %(return_type)s() const { %(body)s }"
|
||||
function = "%(return_type)s %(schema_name)s::%(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
|
||||
const_function = "%(return_type)s %(schema_name)s::%(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
|
||||
constructor = "%(schema_name)s::%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
|
||||
constructor_single_initlist = "%(schema_name)s::%(class_name)s::%(class_name)s(%(arguments)s) : %(superclass)s(%(superclass_init)s) { %(body)s }"
|
||||
cast_function = "%(schema_name)s::%(class_name)s::operator %(return_type)s() const { %(body)s }"
|
||||
|
||||
array_type = "std::vector< %(instance_type)s > /*[%(lower)s:%(upper)s]*/"
|
||||
nested_array_type = "std::vector< std::vector< %(instance_type)s > >"
|
||||
list_type = "IfcTemplatedEntityList< %(instance_type)s >::ptr"
|
||||
list_list_type = "IfcTemplatedEntityListList< %(instance_type)s >::ptr"
|
||||
untyped_list = "IfcEntityList::ptr"
|
||||
@@ -406,31 +196,31 @@ inverse_attr = "IfcTemplatedEntityList< %(entity)s >::ptr %(name)s() const; // I
|
||||
enum_from_string_stmt = ' if (s == "%(value)s") return ::%(schema_name)s::%(name)s::%(short_name)s_%(value)s;'
|
||||
|
||||
schema_entity_stmt = ' case Type::%(name)s: return new %(name)s(e); break;'
|
||||
schema_simple_stmt = ' case Type::%(name)s: return new IfcUtil::IfcEntitySelect(e); break;'
|
||||
string_map_statement = ' string_map["%(uppercase_name)s"%(padding)s] = Type::%(name)s;'
|
||||
parent_type_stmt = ' if(v==%(name)s%(padding)s) { return %(parent)s; }'
|
||||
|
||||
parent_type_test = " || %s::is(v)"
|
||||
|
||||
optional_attr_stmt = "return !entity->getArgument(%(index)d)->isNull();"
|
||||
optional_attr_stmt = "return !data_->getArgument(%(index)d)->isNull();"
|
||||
|
||||
get_attr_stmt = "return *entity->getArgument(%(index)d);"
|
||||
get_attr_stmt_enum = "return %(type)s::FromString(*entity->getArgument(%(index)d));"
|
||||
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*entity->getArgument(%(index)d)));"
|
||||
get_attr_stmt_array = "IfcEntityList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
get_attr_stmt = "return *data_->getArgument(%(index)d);"
|
||||
get_attr_stmt_enum = "return %(type)s::FromString(*data_->getArgument(%(index)d));"
|
||||
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*data_->getArgument(%(index)d)));"
|
||||
get_attr_stmt_array = "IfcEntityList::ptr es = *data_->getArgument(%(index)d); return es->as< %(list_instance_type)s >();"
|
||||
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *data_->getArgument(%(index)d); return es->as< %(list_instance_type)s >();"
|
||||
|
||||
get_inverse = "return entity->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
|
||||
get_inverse = "return data_->getInverse(%(schema_name_upper)s_%(type)s_type, %(index)d)->as<%(type)s>();"
|
||||
|
||||
set_attr_stmt = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v);"
|
||||
set_attr_stmt_enum = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v,%(type)s::ToString(v));"
|
||||
set_attr_stmt_array = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v->generalize());"
|
||||
set_attr_stmt = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(v" +");data_->setArgument(%(index)d,attr);}"
|
||||
set_attr_stmt_enum = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(IfcWrite::IfcWriteArgument::EnumerationReference(v,%(type)s::ToString(v)));data_->setArgument(%(index)d,attr);}"
|
||||
set_attr_stmt_array = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(v->generalize()" +");data_->setArgument(%(index)d,attr);}"
|
||||
|
||||
constructor_stmt = " e->setArgument(%(index)d,(%(name)s));"
|
||||
constructor_stmt_enum = " e->setArgument(%(index)d,%(name)s,%(type)s::ToString(%(name)s));"
|
||||
constructor_stmt_array = " e->setArgument(%(index)d,(%(name)s)->generalize());"
|
||||
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { e->setArgument(%(index)d); }"
|
||||
constructor_stmt_derived = " e->setArgumentDerived(%(index)d);"
|
||||
constructor_stmt = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set((%(name)s)" +");data_->setArgument(%(index)d,attr);}"
|
||||
constructor_stmt_enum = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set((IfcWrite::IfcWriteArgument::EnumerationReference(%(name)s,%(type)s::ToString(%(name)s)))" +");data_->setArgument(%(index)d,attr);}"
|
||||
constructor_stmt_array = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set((%(name)s)->generalize()" +");data_->setArgument(%(index)d,attr);}"
|
||||
constructor_stmt_derived = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(IfcWrite::IfcWriteArgument::Derived()" +");data_->setArgument(%(index)d,attr);}"
|
||||
|
||||
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(boost::blank()); data_->setArgument(%(index)d, attr); }"
|
||||
|
||||
inverse_implementation = " inverse_map[Type::%(type)s].insert(std::make_pair(\"%(name)s\", std::make_pair(Type::%(related_type)s, %(index)d)));"
|
||||
|
||||
|
||||
+351
-81
@@ -20,8 +20,14 @@
|
||||
#ifndef IFCGEOM_H
|
||||
#define IFCGEOM_H
|
||||
|
||||
#define ALMOST_ZERO (1e-9)
|
||||
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < ALMOST_ZERO)
|
||||
#include <cmath>
|
||||
|
||||
static const double ALMOST_ZERO = 1.e-9;
|
||||
|
||||
template <typename T>
|
||||
inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMOST_ZERO) {
|
||||
return fabs(a-b) < tolerance;
|
||||
}
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
@@ -37,70 +43,227 @@
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <TColgp_SequenceOfPnt.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <BOPAlgo_Operation.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
|
||||
#include "../ifcparse/macros.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
#include "../ifcgeom/IfcGeomShapeType.h"
|
||||
|
||||
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->entity->id());\
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
|
||||
// Define this in case you want to conserve memory usage at all cost. This has been
|
||||
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
|
||||
// #define NO_CACHE
|
||||
|
||||
#ifdef NO_CACHE
|
||||
|
||||
#define IN_CACHE(T,E,t,e)
|
||||
#define CACHE(T,E,e)
|
||||
|
||||
#else
|
||||
|
||||
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->data().id());\
|
||||
if ( it != cache.T.end() ) { e = it->second; return true; }
|
||||
#define CACHE(T,E,e) cache.T[E->entity->id()] = e;
|
||||
#define CACHE(T,E,e) cache.T[E->data().id()] = e;
|
||||
|
||||
#endif
|
||||
|
||||
#define INCLUDE_PARENT_DIR(x) STRINGIFY(../ifcparse/x.h)
|
||||
#include INCLUDE_PARENT_DIR(IfcSchema)
|
||||
|
||||
namespace IfcGeom {
|
||||
class IFC_GEOM_API geometry_exception : public std::exception {
|
||||
protected:
|
||||
std::string message;
|
||||
public:
|
||||
geometry_exception(const std::string& m)
|
||||
: message(m) {}
|
||||
virtual ~geometry_exception() throw () {}
|
||||
virtual const char* what() const throw() {
|
||||
return message.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class Cache {
|
||||
class IFC_GEOM_API too_many_faces_exception : public geometry_exception {
|
||||
public:
|
||||
too_many_faces_exception()
|
||||
: geometry_exception("Too many faces for operation") {}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API MAKE_TYPE_NAME(Cache) {
|
||||
public:
|
||||
#include "IfcRegisterCreateCache.h"
|
||||
std::map<int, SurfaceStyle> Style;
|
||||
std::map<int, TopoDS_Shape> Shape;
|
||||
};
|
||||
|
||||
class Kernel {
|
||||
class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::Kernel {
|
||||
private:
|
||||
Cache cache;
|
||||
public:
|
||||
// Tolerances and settings for various geometrical operations:
|
||||
enum GeomValue {
|
||||
// Specifies the deflection of the mesher
|
||||
// Default: 0.001m / 1mm
|
||||
GV_DEFLECTION_TOLERANCE,
|
||||
// Specifies the tolerance of the wire builder, most notably for trimmed curves
|
||||
// Defailt: 0.0001m / 0.1mm
|
||||
GV_WIRE_CREATION_TOLERANCE,
|
||||
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
|
||||
// Default: 0.000001m 0.01cm2
|
||||
GV_MINIMAL_FACE_AREA,
|
||||
// Specifies the treshold distance under which cartesian points are deemed equal
|
||||
// Default: 0.00001m / 0.01mm
|
||||
GV_POINT_EQUALITY_TOLERANCE,
|
||||
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
|
||||
// that consist of many faces is really detrimental for the performance.
|
||||
// Default: 1000
|
||||
GV_MAX_FACES_TO_SEW,
|
||||
// By default singular faces have no explicitly defined orientation, to
|
||||
// force faces to be defined CounterClockWise, set this value greater than zero.
|
||||
GV_FORCE_CCW_FACE_ORIENTATION,
|
||||
// The length unit used the creation of TopoDS_Shapes, primarily affects the
|
||||
// interpretation of IfcCartesianPoints and IfcVector magnitudes
|
||||
// DefaultL 1.0
|
||||
GV_LENGTH_UNIT,
|
||||
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
|
||||
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
|
||||
// Default: -1.0 (= not set, fist try degrees, then radians)
|
||||
GV_PLANEANGLE_UNIT,
|
||||
// The precision used in boolean operations, setting this value too low results
|
||||
// in artefacts and potentially modelling failures
|
||||
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
|
||||
GV_PRECISION
|
||||
|
||||
/*
|
||||
faceset_helper traverses the forward instance references of IfcConnectedFaceSet and then provides a mapping
|
||||
M of (IfcCartesianPoint, IfcCartesianPoint) -> TopoDS_Edge, where M(a, b) is a partner of M(b, a), ie share
|
||||
the same underlying edge but with orientation reversed. This then later speeds op the process of creating a
|
||||
manifold Shell / Solid from this set of faces. Only IfcPolyLoop instances are used. Points within the tolerance
|
||||
threshiold are merged, so consider points a, b, c, distance(a, b) < eps then M(a, b) = Null, M(a, b) = M(a, c).
|
||||
*/
|
||||
class faceset_helper {
|
||||
private:
|
||||
MAKE_TYPE_NAME(Kernel)* kernel_;
|
||||
std::set<const IfcSchema::IfcPolyLoop*> duplicates_;
|
||||
std::map<int, int> vertex_mapping_;
|
||||
std::map<std::pair<int, int>, TopoDS_Edge> edges_;
|
||||
double eps_;
|
||||
bool non_manifold_;
|
||||
|
||||
template <typename Fn>
|
||||
void loop_(IfcSchema::IfcCartesianPoint::list::ptr& ps, const Fn& callback) {
|
||||
if (ps->size() < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto a = *(ps->end() - 1);
|
||||
auto A = a->data().id();
|
||||
for (auto& b : *ps) {
|
||||
auto B = b->data().id();
|
||||
auto C = vertex_mapping_[A], D = vertex_mapping_[B];
|
||||
bool fwd = C < D;
|
||||
if (!fwd) {
|
||||
std::swap(C, D);
|
||||
}
|
||||
if (C != D) {
|
||||
callback(C, D, fwd);
|
||||
A = B;
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
faceset_helper(MAKE_TYPE_NAME(Kernel)* kernel, const IfcSchema::IfcConnectedFaceSet* l);
|
||||
|
||||
~faceset_helper();
|
||||
|
||||
bool non_manifold() const { return non_manifold_; }
|
||||
bool& non_manifold() { return non_manifold_; }
|
||||
|
||||
bool edge(const IfcSchema::IfcCartesianPoint* a, const IfcSchema::IfcCartesianPoint* b, TopoDS_Edge& e) {
|
||||
int A = vertex_mapping_[a->data().id()];
|
||||
int B = vertex_mapping_[b->data().id()];
|
||||
if (A == B) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return edge(A, B, e);
|
||||
}
|
||||
|
||||
bool edge(int A, int B, TopoDS_Edge& e) {
|
||||
auto it = edges_.find({A, B});
|
||||
if (it == edges_.end()) {
|
||||
return false;
|
||||
}
|
||||
e = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wire(const IfcSchema::IfcPolyLoop* loop, TopoDS_Wire& wire) {
|
||||
if (duplicates_.find(loop) != duplicates_.end()) {
|
||||
return false;
|
||||
}
|
||||
BRep_Builder builder;
|
||||
builder.MakeWire(wire);
|
||||
int count = 0;
|
||||
auto ps = loop->Polygon();
|
||||
loop_(ps, [this, &builder, &wire, &count](int A, int B, bool fwd) {
|
||||
TopoDS_Edge e;
|
||||
if (edge(A, B, e)) {
|
||||
if (!fwd) {
|
||||
e.Reverse();
|
||||
}
|
||||
builder.Add(wire, e);
|
||||
count += 1;
|
||||
}
|
||||
});
|
||||
if (count >= 3) {
|
||||
wire.Closed(true);
|
||||
|
||||
TopTools_ListOfShape results;
|
||||
if (kernel_->wire_intersections(wire, results)) {
|
||||
Logger::Warning("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected", loop);
|
||||
kernel_->select_largest(results, wire);
|
||||
non_manifold_ = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
double epsilon() const {
|
||||
return eps_;
|
||||
}
|
||||
};
|
||||
|
||||
double deflection_tolerance;
|
||||
double ifc_length_unit;
|
||||
double ifc_planeangle_unit;
|
||||
double modelling_precision;
|
||||
double dimensionality;
|
||||
double max_faces_to_orient;
|
||||
|
||||
#ifndef NO_CACHE
|
||||
MAKE_TYPE_NAME(Cache) cache;
|
||||
#endif
|
||||
|
||||
std::map<int, SurfaceStyle> style_cache;
|
||||
|
||||
const SurfaceStyle* internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_style);
|
||||
|
||||
// For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf)
|
||||
const IfcParse::declaration* placement_rel_to;
|
||||
|
||||
faceset_helper* faceset_helper_;
|
||||
|
||||
public:
|
||||
MAKE_TYPE_NAME(Kernel)()
|
||||
: IfcGeom::Kernel(0)
|
||||
, deflection_tolerance(0.001)
|
||||
, max_faces_to_orient(-1.0)
|
||||
, ifc_length_unit(1.0)
|
||||
, ifc_planeangle_unit(-1.0)
|
||||
, modelling_precision(0.00001)
|
||||
, dimensionality(1.)
|
||||
, placement_rel_to(0)
|
||||
, faceset_helper_(nullptr)
|
||||
{}
|
||||
|
||||
MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other) : IfcGeom::Kernel(0) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
MAKE_TYPE_NAME(Kernel)& operator=(const MAKE_TYPE_NAME(Kernel)& other) {
|
||||
setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE));
|
||||
setValue(GV_MAX_FACES_TO_ORIENT, other.getValue(GV_MAX_FACES_TO_ORIENT));
|
||||
setValue(GV_LENGTH_UNIT, other.getValue(GV_LENGTH_UNIT));
|
||||
setValue(GV_PLANEANGLE_UNIT, other.getValue(GV_PLANEANGLE_UNIT));
|
||||
setValue(GV_PRECISION, other.getValue(GV_PRECISION));
|
||||
setValue(GV_DIMENSIONALITY, other.getValue(GV_DIMENSIONALITY));
|
||||
setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
|
||||
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
|
||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result);
|
||||
bool is_shape_collection(const IfcUtil::IfcBaseClass* L);
|
||||
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
|
||||
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
|
||||
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
|
||||
@@ -108,8 +271,43 @@ public:
|
||||
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
void assert_closed_wire(TopoDS_Wire& wire);
|
||||
|
||||
bool convert_layerset(const IfcSchema::IfcProduct*, std::vector<Handle_Geom_Surface>&, std::vector<const SurfaceStyle*>&, std::vector<double>&);
|
||||
bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
|
||||
bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
|
||||
bool fold_layers(const IfcSchema::IfcWall*, const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
|
||||
|
||||
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&);
|
||||
bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&);
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&);
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&);
|
||||
#else
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
#endif
|
||||
|
||||
bool fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b, TopoDS_Shape& box, double& height);
|
||||
|
||||
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&);
|
||||
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&);
|
||||
const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&);
|
||||
bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&);
|
||||
bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&);
|
||||
bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector<gp_Pnt>&);
|
||||
bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair<Handle_Geom_Surface, Handle_Geom_Curve> >&);
|
||||
bool closest(const gp_Pnt&, const std::vector<gp_Pnt>&, gp_Pnt&);
|
||||
bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
|
||||
bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen=0.1);
|
||||
|
||||
bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end);
|
||||
|
||||
IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item);
|
||||
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item);
|
||||
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
|
||||
bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid);
|
||||
bool is_compound(const TopoDS_Shape& shape);
|
||||
bool is_convex(const TopoDS_Wire& wire);
|
||||
TopoDS_Shape halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent);
|
||||
@@ -117,68 +315,140 @@ public:
|
||||
gp_Pnt point_above_plane(const gp_Pln& pln, bool agree=true);
|
||||
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid);
|
||||
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face);
|
||||
double shape_volume(const TopoDS_Shape& s);
|
||||
double face_area(const TopoDS_Face& f);
|
||||
void apply_tolerance(TopoDS_Shape& s, double t);
|
||||
void setValue(GeomValue var, double value);
|
||||
double getValue(GeomValue var);
|
||||
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
|
||||
void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||
void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||
void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||
bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
|
||||
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
|
||||
bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&, double eps=-1.);
|
||||
bool flatten_wire(TopoDS_Wire&);
|
||||
/// Triangulate the set of wires. The firstmost wire is assumed to be the outer wire.
|
||||
bool triangulate_wire(const std::vector<TopoDS_Wire>&, TopTools_ListOfShape&);
|
||||
bool wire_intersections(const TopoDS_Wire & wire, TopTools_ListOfShape & wires);
|
||||
void select_largest(const TopTools_ListOfShape& shapes, TopoDS_Shape& largest);
|
||||
|
||||
static double shape_volume(const TopoDS_Shape& s);
|
||||
static double face_area(const TopoDS_Face& f);
|
||||
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&);
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&);
|
||||
|
||||
bool is_identity_transform(IfcUtil::IfcBaseClass*);
|
||||
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr find_openings(IfcSchema::IfcProduct* product);
|
||||
|
||||
IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&);
|
||||
|
||||
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
|
||||
|
||||
IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::BRepElement<P, PP>* create_brep_for_representation_and_product(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
|
||||
|
||||
template <typename P>
|
||||
IfcGeom::BRepElement<P>* create_brep_for_representation_and_product(const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::BRepElement<P, PP>* create_brep_for_processed_representation(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::BRepElement<P, PP>*);
|
||||
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item);
|
||||
const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct*);
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation);
|
||||
IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation*);
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*);
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*);
|
||||
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
|
||||
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
|
||||
for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
|
||||
#ifdef USE_IFC4
|
||||
IfcUtil::IfcAbstractSelect::list::ptr style_assignments = (*jt)->Styles();
|
||||
for (IfcUtil::IfcAbstractSelect::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
|
||||
continue;
|
||||
}
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
|
||||
IfcEntityList::ptr style_assignments = si->Styles();
|
||||
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) {
|
||||
continue;
|
||||
}
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
|
||||
#else
|
||||
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = (*jt)->Styles();
|
||||
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
|
||||
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = si->Styles();
|
||||
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
|
||||
#endif
|
||||
IfcEntityList::ptr styles = style_assignment->Styles();
|
||||
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
|
||||
IfcUtil::IfcBaseClass* style = *lt;
|
||||
if (style->is(IfcSchema::Type::IfcSurfaceStyle)) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
IfcEntityList::ptr styles_elements = surface_style->Styles();
|
||||
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
|
||||
if ((*mt)->is(T::Class())) {
|
||||
return std::make_pair(surface_style, (T*) *mt);
|
||||
}
|
||||
IfcEntityList::ptr styles = style_assignment->Styles();
|
||||
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
|
||||
IfcUtil::IfcBaseClass* style = *lt;
|
||||
if (style->declaration().is(IfcSchema::IfcSurfaceStyle::Class())) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
IfcEntityList::ptr styles_elements = surface_style->Styles();
|
||||
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
|
||||
if ((*mt)->declaration().is(T::Class())) {
|
||||
return std::make_pair(surface_style, (T*) *mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we
|
||||
// break after encountering the first IfcStyledItem
|
||||
break;
|
||||
}
|
||||
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
|
||||
}
|
||||
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
|
||||
// For certain representation items, most notably boolean operands,
|
||||
// a style definition might reside on one of its operands.
|
||||
representation_item = find_item_carrying_style(representation_item);
|
||||
|
||||
if (representation_item->as<IfcSchema::IfcStyledItem>()) {
|
||||
return _get_surface_style<T>(representation_item->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
|
||||
if (styled_items->size()) {
|
||||
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we return after the first IfcStyledItem:
|
||||
return _get_surface_style<T>(*styled_items->begin());
|
||||
}
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
|
||||
}
|
||||
|
||||
void purge_cache() {
|
||||
// Rather hack-ish, but a stopgap solution to keep memory under control
|
||||
// for large files. SurfaceStyles need to be kept at all costs, as they
|
||||
// are read later on when serializing Collada files.
|
||||
#ifndef NO_CACHE
|
||||
cache = MAKE_TYPE_NAME(Cache)();
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_conversion_placement_rel_to(const IfcParse::declaration* type);
|
||||
|
||||
#include "IfcRegisterGeomHeader.h"
|
||||
|
||||
virtual void setValue(GeomValue var, double value);
|
||||
virtual double getValue(GeomValue var) const;
|
||||
|
||||
virtual IfcGeom::BRepElement<double>* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
{
|
||||
return create_brep_for_representation_and_product<double, double>(settings, (IfcSchema::IfcRepresentation*) representation, (IfcSchema::IfcProduct*) product);
|
||||
}
|
||||
|
||||
virtual IfcRepresentationShapeItems convert(IfcUtil::IfcBaseClass* item) {
|
||||
IfcRepresentationShapeItems items;
|
||||
bool success = convert_shapes(item, items);
|
||||
if (!success) {
|
||||
throw IfcParse::IfcException("Failed to process representation item");
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) {
|
||||
if (item->as<IfcSchema::IfcObjectPlacement>()) {
|
||||
return convert(item->as<IfcSchema::IfcObjectPlacement>(), trsf);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr es);
|
||||
IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(tesselate_)(const TopoDS_Shape& shape, double deflection);
|
||||
IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& shape, bool advanced);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -77,17 +77,23 @@
|
||||
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
}
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
@@ -102,7 +108,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)
|
||||
double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
}
|
||||
// Open Cascade does not allow ellipses of which the minor radius
|
||||
@@ -112,7 +118,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)
|
||||
const bool rotated = y > x;
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) {
|
||||
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
@@ -135,4 +141,58 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& c
|
||||
// See note at IfcGeomWires.cpp:237
|
||||
curve = new Geom_Line(pnt,vec);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Handle(Geom_Curve)& curve) {
|
||||
|
||||
const bool is_rational = l->declaration().is(IfcSchema::IfcRationalBSplineCurveWithKnots::Class());
|
||||
|
||||
const IfcSchema::IfcCartesianPoint::list::ptr cps = l->ControlPointsList();
|
||||
const std::vector<int> mults = l->KnotMultiplicities();
|
||||
const std::vector<double> knots = l->Knots();
|
||||
|
||||
TColgp_Array1OfPnt Poles(0, cps->size() - 1);
|
||||
TColStd_Array1OfReal Weights(0, cps->size() - 1);
|
||||
TColStd_Array1OfReal Knots(0, (int)knots.size() - 1);
|
||||
TColStd_Array1OfInteger Mults(0, (int)mults.size() - 1);
|
||||
Standard_Integer Degree = l->Degree();
|
||||
Standard_Boolean Periodic = l->ClosedCurve();
|
||||
|
||||
int i;
|
||||
|
||||
if (is_rational) {
|
||||
IfcSchema::IfcRationalBSplineCurveWithKnots* rl = (IfcSchema::IfcRationalBSplineCurveWithKnots*)l;
|
||||
std::vector<double> weights = rl->WeightsData();
|
||||
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it, ++i) {
|
||||
Weights(i) = *it;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (IfcSchema::IfcCartesianPoint::list::it it = cps->begin(); it != cps->end(); ++it, ++i) {
|
||||
gp_Pnt pnt;
|
||||
if (!convert(*it, pnt)) return false;
|
||||
Poles(i) = pnt;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (std::vector<int>::const_iterator it = mults.begin(); it != mults.end(); ++it, ++i) {
|
||||
Mults(i) = *it;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = knots.begin(); it != knots.end(); ++it, ++i) {
|
||||
Knots(i) = *it;
|
||||
}
|
||||
|
||||
if (is_rational) {
|
||||
curve = new Geom_BSplineCurve(Poles, Weights, Knots, Mults, Degree, Periodic);
|
||||
} else {
|
||||
curve = new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
+116
-35
@@ -20,9 +20,14 @@
|
||||
#ifndef IFCGEOMELEMENT_H
|
||||
#define IFCGEOMELEMENT_H
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
@@ -40,7 +45,7 @@ namespace IfcGeom {
|
||||
for(int i = 1; i < 5; ++i) {
|
||||
for (int j = 1; j < 4; ++j) {
|
||||
const double trsf_value = trsf.Value(j,i);
|
||||
const double matrix_value = i == 4 && settings.convert_back_units()
|
||||
const double matrix_value = i == 4 && settings.get(IteratorSettings::CONVERT_BACK_UNITS)
|
||||
? trsf_value / settings.unit_magnitude()
|
||||
: trsf_value;
|
||||
_data.push_back(static_cast<P>(matrix_value));
|
||||
@@ -53,18 +58,28 @@ namespace IfcGeom {
|
||||
template <typename P>
|
||||
class Transformation {
|
||||
private:
|
||||
gp_Trsf trsf;
|
||||
Matrix<P> _matrix;
|
||||
ElementSettings settings_;
|
||||
gp_Trsf trsf_;
|
||||
Matrix<P> matrix_;
|
||||
public:
|
||||
Transformation(const ElementSettings& settings, const gp_Trsf& trsf)
|
||||
: trsf(trsf)
|
||||
, _matrix(settings, trsf)
|
||||
: settings_(settings)
|
||||
, trsf_(trsf)
|
||||
, matrix_(settings, trsf)
|
||||
{}
|
||||
const gp_Trsf& data() const { return trsf; }
|
||||
const Matrix<P>& matrix() const { return _matrix; }
|
||||
const gp_Trsf& data() const { return trsf_; }
|
||||
const Matrix<P>& matrix() const { return matrix_; }
|
||||
|
||||
Transformation inverted() const {
|
||||
return Transformation(settings_, trsf_.Inverted());
|
||||
}
|
||||
|
||||
Transformation multiplied(const Transformation& other) const {
|
||||
return Transformation(settings_, trsf_.Multiplied(other.data()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
template <typename P = double, typename PP = P>
|
||||
class Element {
|
||||
private:
|
||||
int _id;
|
||||
@@ -72,64 +87,130 @@ namespace IfcGeom {
|
||||
std::string _name;
|
||||
std::string _type;
|
||||
std::string _guid;
|
||||
Transformation<P> _transformation;
|
||||
std::string _context;
|
||||
std::string _unique_id;
|
||||
Transformation<PP> _transformation;
|
||||
IfcUtil::IfcBaseEntity* product_;
|
||||
std::vector<const IfcGeom::Element<P, PP>*> _parents;
|
||||
public:
|
||||
|
||||
friend bool operator == (const Element<P, PP> & element1, const Element<P, PP> & element2) {
|
||||
return element1.id() == element2.id();
|
||||
}
|
||||
|
||||
// Use the id to compare, or the elevation is the elements are IfcBuildingStoreys and the elevation is set
|
||||
friend bool operator < (const Element<P, PP> & element1, const Element<P, PP> & element2) {
|
||||
if (element1.type() == "IfcBuildingStorey" && element2.type() == "IfcBuildingStorey") {
|
||||
size_t attr_index = element1.product()->declaration().attribute_index("Elevation");
|
||||
Argument* elev_attr1 = element1.product()->data().getArgument(attr_index);
|
||||
Argument* elev_attr2 = element2.product()->data().getArgument(attr_index);
|
||||
|
||||
if (!elev_attr1->isNull() && !elev_attr2->isNull()) {
|
||||
double elev1 = *elev_attr1;
|
||||
double elev2 = *elev_attr2;
|
||||
|
||||
return elev1 < elev2;
|
||||
}
|
||||
}
|
||||
|
||||
return element1.id() < element2.id();
|
||||
}
|
||||
|
||||
int id() const { return _id; }
|
||||
int parent_id() const { return _parent_id; }
|
||||
const std::string& name() const { return _name; }
|
||||
const std::string& type() const { return _type; }
|
||||
const std::string& guid() const { return _guid; }
|
||||
const Transformation<P>& transformation() const { return _transformation; }
|
||||
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf)
|
||||
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _transformation(settings, trsf)
|
||||
{}
|
||||
const std::string& context() const { return _context; }
|
||||
const std::string& unique_id() const { return _unique_id; }
|
||||
const Transformation<PP>& transformation() const { return _transformation; }
|
||||
IfcUtil::IfcBaseEntity* product() const { return product_; }
|
||||
const std::vector<const IfcGeom::Element<P, PP>*> parents() const { return _parents; }
|
||||
void SetParents(std::vector<const IfcGeom::Element<P, PP>*> newparents) { _parents = newparents; }
|
||||
|
||||
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type,
|
||||
const std::string& guid, const std::string& context, const gp_Trsf& trsf, IfcUtil::IfcBaseEntity* product)
|
||||
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
|
||||
, product_(product)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
if (type == "IfcProject") {
|
||||
oss << "project";
|
||||
} else {
|
||||
try {
|
||||
oss << "product-" << IfcParse::IfcGlobalId(guid).formatted();
|
||||
} catch (const std::exception& e) {
|
||||
oss << "product";
|
||||
Logger::Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_context.empty()) {
|
||||
std::string ctx = _context;
|
||||
boost::to_lower(ctx);
|
||||
boost::replace_all(ctx, " ", "-");
|
||||
oss << "-" << ctx;
|
||||
}
|
||||
|
||||
_unique_id = oss.str();
|
||||
}
|
||||
virtual ~Element() {}
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class BRepElement : public Element<P> {
|
||||
template <typename P = double, typename PP = P>
|
||||
class BRepElement : public Element<P, PP> {
|
||||
private:
|
||||
Representation::BRep* _geometry;
|
||||
boost::shared_ptr<Representation::BRep> _geometry;
|
||||
public:
|
||||
const boost::shared_ptr<Representation::BRep>& geometry_pointer() const { return _geometry; }
|
||||
const Representation::BRep& geometry() const { return *_geometry; }
|
||||
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf, Representation::BRep* geometry)
|
||||
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,trsf)
|
||||
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid,
|
||||
const std::string& context, const gp_Trsf& trsf, const boost::shared_ptr<Representation::BRep>& geometry,
|
||||
IfcUtil::IfcBaseEntity* product)
|
||||
: Element<P, PP>(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
virtual ~BRepElement() {
|
||||
delete _geometry;
|
||||
|
||||
bool calculate_projected_surface_area(double& along_x, double& along_y, double& along_z) const {
|
||||
const auto& trsf = this->transformation().data();
|
||||
const gp_Mat& mat = trsf.HVectorialPart();
|
||||
gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1));
|
||||
return geometry().calculate_projected_surface_area(ax, along_x, along_y, along_z);
|
||||
}
|
||||
private:
|
||||
BRepElement(const BRepElement& other);
|
||||
BRepElement& operator=(const BRepElement& other);
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class TriangulationElement : public Element<P> {
|
||||
template <typename P = double, typename PP = P>
|
||||
class TriangulationElement : public Element<P, PP> {
|
||||
private:
|
||||
Representation::Triangulation<P>* _geometry;
|
||||
boost::shared_ptr< Representation::Triangulation<P> > _geometry;
|
||||
public:
|
||||
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
|
||||
TriangulationElement(const BRepElement<P>& shape_model)
|
||||
: Element<P>(shape_model)
|
||||
, _geometry(new Representation::Triangulation<P>(shape_model.geometry()))
|
||||
const boost::shared_ptr< Representation::Triangulation<P> >& geometry_pointer() const { return _geometry; }
|
||||
TriangulationElement(const BRepElement<P, PP>& shape_model)
|
||||
: Element<P, PP>(shape_model)
|
||||
, _geometry(boost::shared_ptr<Representation::Triangulation<P> >(new Representation::Triangulation<P>(shape_model.geometry())))
|
||||
{}
|
||||
TriangulationElement(const Element<P, PP>& element, const boost::shared_ptr<Representation::Triangulation<P> >& geometry)
|
||||
: Element<P, PP>(element)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
virtual ~TriangulationElement() {
|
||||
delete _geometry;
|
||||
}
|
||||
private:
|
||||
TriangulationElement(const TriangulationElement& other);
|
||||
TriangulationElement& operator=(const TriangulationElement& other);
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class SerializedElement : public Element<P> {
|
||||
template <typename P = double, typename PP = P>
|
||||
class SerializedElement : public Element<P, PP> {
|
||||
private:
|
||||
Representation::Serialization* _geometry;
|
||||
public:
|
||||
const Representation::Serialization& geometry() const { return *_geometry; }
|
||||
SerializedElement(const BRepElement<P>& shape_model)
|
||||
: Element<P>(shape_model)
|
||||
SerializedElement(const BRepElement<P, PP>& shape_model)
|
||||
: Element<P, PP>(shape_model)
|
||||
, _geometry(new Representation::Serialization(shape_model.geometry()))
|
||||
{}
|
||||
virtual ~SerializedElement() {
|
||||
@@ -141,4 +222,4 @@ namespace IfcGeom {
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+481
-193
@@ -47,6 +47,7 @@
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
@@ -66,13 +67,16 @@
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS_Iterator.hxx>
|
||||
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
#include <ShapeFix_Edge.hxx>
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <ShapeFix_Solid.hxx>
|
||||
@@ -83,167 +87,398 @@
|
||||
#include <Standard_Failure.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepCheck_Face.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#include <TopTools_DataMapOfShapeInteger.hxx>
|
||||
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
||||
|
||||
#include <BRepLib_FindSurface.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <BRepCheck_Face.hxx>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
IfcSchema::IfcFaceBound::list::it it = bounds->begin();
|
||||
IfcSchema::IfcLoop* loop = (*it)->Bound();
|
||||
TopoDS_Wire outer_wire;
|
||||
if ( ! convert_wire(loop,outer_wire) ) return false;
|
||||
BRepBuilderAPI_MakeFace mf (outer_wire);
|
||||
BRepBuilderAPI_FaceError er = mf.Error();
|
||||
if ( er == BRepBuilderAPI_NotPlanar ) {
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(outer_wire, 0.01, TopAbs_WIRE);
|
||||
mf.~BRepBuilderAPI_MakeFace();
|
||||
new (&mf) BRepBuilderAPI_MakeFace(outer_wire);
|
||||
er = mf.Error();
|
||||
}
|
||||
if ( er != BRepBuilderAPI_FaceDone ) return false;
|
||||
if ( bounds->size() == 1 ) {
|
||||
face = mf.Face();
|
||||
} else {
|
||||
for( ++it; it != bounds->end(); ++ it) {
|
||||
IfcSchema::IfcLoop* loop = (*it)->Bound();
|
||||
TopoDS_Wire wire;
|
||||
if ( ! convert_wire(loop,wire) ) return false;
|
||||
mf.Add(wire);
|
||||
}
|
||||
if ( mf.IsDone() ) {
|
||||
ShapeFix_Shape sfs(mf.Face());
|
||||
sfs.Perform();
|
||||
TopoDS_Shape sfs_shape = sfs.Shape();
|
||||
bool is_face = sfs_shape.ShapeType() == TopAbs_FACE;
|
||||
if ( is_face ) {
|
||||
face = TopoDS::Face(sfs_shape);
|
||||
} else {
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
namespace {
|
||||
/* Returns whether wire conforms to a polyhedron, i.e. only edges with linear curves*/
|
||||
bool is_polyhedron(const TopoDS_Wire& wire) {
|
||||
double a, b;
|
||||
TopLoc_Location l;
|
||||
|
||||
TopoDS_Iterator it(wire, false, false);
|
||||
for (; it.More(); it.Next()) {
|
||||
auto crv = BRep_Tool::Curve(TopoDS::Edge(it.Value()), l, a, b);
|
||||
if (!crv || crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( getValue(GV_FORCE_CCW_FACE_ORIENTATION)>0 ) {
|
||||
// Check the orientation of the face by comparing the
|
||||
// normal of the topological surface to the Newell's Method's
|
||||
// normal. Newell's Method is used for the normal calculation
|
||||
// as a simple edge cross product can give opposite results
|
||||
// for a concave face boundary.
|
||||
// Reference: Graphics Gems III p. 231
|
||||
BRepGProp_Face prop(TopoDS::Face(face));
|
||||
gp_Vec normal_direction;
|
||||
gp_Pnt center;
|
||||
double u1,u2,v1,v2;
|
||||
prop.Bounds(u1,u2,v1,v2);
|
||||
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal_direction);
|
||||
gp_Dir face_normal1 = gp_Dir(normal_direction.XYZ());
|
||||
/* A temporary structure to store the intermediate data for the face conversion */
|
||||
class face_definition {
|
||||
private:
|
||||
Handle(Geom_Surface) surface_;
|
||||
std::vector<TopoDS_Wire> wires_;
|
||||
bool all_outer_;
|
||||
public:
|
||||
face_definition() : surface_(), all_outer_(false) {}
|
||||
|
||||
double x = 0, y = 0, z = 0;
|
||||
gp_Pnt current, previous, first;
|
||||
int n = 0;
|
||||
// Iterate over the vertices of the outer wire (discarding
|
||||
// any potential holes)
|
||||
for ( TopExp_Explorer exp(outer_wire,TopAbs_VERTEX);; exp.Next()) {
|
||||
unsigned has_more = exp.More();
|
||||
if ( has_more ) {
|
||||
const TopoDS_Vertex& v = TopoDS::Vertex(exp.Current());
|
||||
current = BRep_Tool::Pnt(v);
|
||||
} else {
|
||||
current = first;
|
||||
typedef std::vector<TopoDS_Wire>::const_iterator wire_it;
|
||||
|
||||
bool& all_outer() {
|
||||
return all_outer_;
|
||||
}
|
||||
if ( n ) {
|
||||
const double& xn = previous.X();
|
||||
const double& yn = previous.Y();
|
||||
const double& zn = previous.Z();
|
||||
const double& xn1 = current.X();
|
||||
const double& yn1 = current.Y();
|
||||
const double& zn1 = current.Z();
|
||||
x += (yn-yn1)*(zn+zn1);
|
||||
y += (xn+xn1)*(zn-zn1);
|
||||
z += (xn-xn1)*(yn+yn1);
|
||||
} else {
|
||||
first = current;
|
||||
}
|
||||
if ( !has_more ) {
|
||||
break;
|
||||
}
|
||||
previous = current;
|
||||
++n;
|
||||
}
|
||||
|
||||
// If Newell's normal does not point in the same direction
|
||||
// as the topological face normal the face orientation is
|
||||
// reversed
|
||||
gp_Vec face_normal2(x,y,z);
|
||||
|
||||
if (face_normal2.Magnitude() > ALMOST_ZERO) {
|
||||
if ( face_normal1.Dot(face_normal2) < 0 ) {
|
||||
TopAbs_Orientation o = face.Orientation();
|
||||
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
|
||||
bool all_outer() const {
|
||||
return all_outer_;
|
||||
}
|
||||
}
|
||||
|
||||
Handle(Geom_Surface)& surface() {
|
||||
return surface_;
|
||||
}
|
||||
|
||||
const Handle(Geom_Surface)& surface() const {
|
||||
return surface_;
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Wire>& wires() {
|
||||
return wires_;
|
||||
}
|
||||
|
||||
const TopoDS_Wire& outer_wire() const {
|
||||
return wires_.front();
|
||||
}
|
||||
|
||||
std::pair<wire_it, wire_it> inner_wires() const {
|
||||
return { wires_.begin() + 1, wires_.end() };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& result) {
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
|
||||
face_definition fd;
|
||||
|
||||
const bool is_face_surface = l->declaration().is(IfcSchema::IfcFaceSurface::Class());
|
||||
|
||||
if (is_face_surface) {
|
||||
IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l;
|
||||
fs->FaceSurface();
|
||||
// FIXME: Surfaces are interpreted as a TopoDS_Shape
|
||||
TopoDS_Shape surface_shape;
|
||||
if (!convert_shape(fs->FaceSurface(), surface_shape)) return false;
|
||||
|
||||
// FIXME: Assert this obtaines the only face
|
||||
TopExp_Explorer exp(surface_shape, TopAbs_FACE);
|
||||
if (!exp.More()) return false;
|
||||
|
||||
TopoDS_Face surface = TopoDS::Face(exp.Current());
|
||||
fd.surface() = BRep_Tool::Surface(surface);
|
||||
}
|
||||
|
||||
// It might be a good idea to globally discard faces
|
||||
// smaller than a certain treshold value. But for now
|
||||
// only when processing IfcConnectedFacesets the small
|
||||
// faces are skipped.
|
||||
// return face_area(face) > 0.0001;
|
||||
const int num_bounds = bounds->size();
|
||||
int num_outer_bounds = 0;
|
||||
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
if (bound->declaration().is(IfcSchema::IfcFaceOuterBound::Class())) num_outer_bounds ++;
|
||||
}
|
||||
|
||||
// The number of outer bounds should be one according to the schema. Also Open Cascade
|
||||
// expects this, but it is not strictly checked. Regardless, if the number is greater,
|
||||
// the face will still be processed as long as there are no holes. A compound of faces
|
||||
// is returned in that case.
|
||||
if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num_outer_bounds > 1) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Multiple outer boundaries for:", l);
|
||||
fd.all_outer() = true;
|
||||
}
|
||||
|
||||
TopTools_DataMapOfShapeInteger wire_senses;
|
||||
|
||||
for (int process_interior = 0; process_interior <= 1; ++process_interior) {
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
IfcSchema::IfcLoop* loop = bound->Bound();
|
||||
|
||||
bool same_sense = bound->Orientation();
|
||||
const bool is_interior =
|
||||
!bound->declaration().is(IfcSchema::IfcFaceOuterBound::Class()) &&
|
||||
(num_bounds > 1) &&
|
||||
(num_outer_bounds < num_bounds);
|
||||
|
||||
// The exterior face boundary is processed first
|
||||
if (is_interior == !process_interior) continue;
|
||||
|
||||
TopoDS_Wire wire;
|
||||
if (faceset_helper_ && loop->as<IfcSchema::IfcPolyLoop>()) {
|
||||
if (!faceset_helper_->wire(loop->as<IfcSchema::IfcPolyLoop>(), wire)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Face boundary loop not included", loop);
|
||||
continue;
|
||||
}
|
||||
} else if (!convert_wire(loop, wire)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!same_sense) {
|
||||
wire.Reverse();
|
||||
}
|
||||
|
||||
wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED);
|
||||
|
||||
fd.wires().emplace_back(wire);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd.wires().empty()) {
|
||||
Logger::Warning("Face with no boundaries", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fd.surface().IsNull()) {
|
||||
// Use the first wire to find a plane manually for polygonal wires
|
||||
const TopoDS_Wire& wire = fd.wires().front();
|
||||
if (is_polyhedron(wire)) {
|
||||
TopExp_Explorer exp(wire, TopAbs_EDGE);
|
||||
int count = 0;
|
||||
TopoDS_Edge edges[2];
|
||||
for (; exp.More(); exp.Next(), count++) {
|
||||
if (count < 2) {
|
||||
edges[count] = TopoDS::Edge(exp.Current());
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 3) {
|
||||
// Help Open Cascade by finding the plane more efficiently
|
||||
double _, __;
|
||||
Handle(Geom_Line) c1 = Handle(Geom_Line)::DownCast(BRep_Tool::Curve(edges[0], _, __));
|
||||
Handle(Geom_Line) c2 = Handle(Geom_Line)::DownCast(BRep_Tool::Curve(edges[1], _, __));
|
||||
|
||||
const gp_Vec ab = c1->Position().Direction();
|
||||
const gp_Vec ac = c2->Position().Direction();
|
||||
const gp_Vec cross = ab.Crossed(ac);
|
||||
|
||||
if (cross.SquareMagnitude() > ALMOST_ZERO) {
|
||||
const gp_Dir n = cross;
|
||||
fd.surface() = new Geom_Plane(c1->Position().Location(), n);
|
||||
}
|
||||
} else {
|
||||
gp_Pln pln;
|
||||
if (approximate_plane_through_wire(wire, pln)) {
|
||||
fd.surface() = new Geom_Plane(pln);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd.surface().IsNull()) {
|
||||
// BRepLib_FindSurface is used in case no surface is found or provided
|
||||
|
||||
const TopoDS_Wire& wire = fd.wires().front();
|
||||
|
||||
BRepLib_FindSurface fs(wire, getValue(GV_PRECISION), true, true);
|
||||
if (fs.Found()) {
|
||||
fd.surface() = fs.Surface();
|
||||
ShapeFix_ShapeTolerance ftol;
|
||||
ftol.SetTolerance(wire, fs.ToleranceReached(), TopAbs_WIRE);
|
||||
}
|
||||
}
|
||||
|
||||
TopTools_ListOfShape face_list;
|
||||
|
||||
if (fd.surface().IsNull()) {
|
||||
// The set of wires is triangulated in case no surface can be found
|
||||
Logger::Message(Logger::LOG_WARNING, "Triangulating face boundaries for face", l);
|
||||
|
||||
if (fd.all_outer()) {
|
||||
for (const auto& w : fd.wires()) {
|
||||
TopTools_ListOfShape fl;
|
||||
triangulate_wire({ w }, fl);
|
||||
face_list.Append(fl);
|
||||
}
|
||||
} else {
|
||||
triangulate_wire(fd.wires(), face_list);
|
||||
}
|
||||
} else if (!fd.all_outer()) {
|
||||
BRepBuilderAPI_MakeFace mf(fd.surface(), fd.outer_wire());
|
||||
|
||||
if (mf.IsDone()) {
|
||||
// Is this necessary
|
||||
TopoDS_Face f = mf.Face();
|
||||
mf.Init(f);
|
||||
|
||||
for (auto it = fd.inner_wires().first; it != fd.inner_wires().second; ++it) {
|
||||
mf.Add(*it);
|
||||
}
|
||||
|
||||
face_list.Append(mf.Face());
|
||||
}
|
||||
} else {
|
||||
for (const auto& w : fd.wires()) {
|
||||
BRepBuilderAPI_MakeFace mf(fd.surface(), w);
|
||||
if (mf.IsDone()) {
|
||||
face_list.Append(mf.Face());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fd.surface().IsNull()) {
|
||||
// Some fixes for orientation and p-curves. If we have no surface, it
|
||||
// means the face has been triangulated in which case none of these
|
||||
// fixes are necessary.
|
||||
|
||||
if (fd.surface()->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
|
||||
// In case of (non-planar) face surface, p-curves need to be computed.
|
||||
// For planar faces, Open Cascade generates p-curves on the fly.
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
// Small chance there are multiple faces
|
||||
const TopoDS_Face& face = TopoDS::Face(it.Value());
|
||||
for (TopExp_Explorer exp2(face, TopAbs_EDGE); exp2.More(); exp2.Next()) {
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(exp2.Current());
|
||||
ShapeFix_Edge fix_edge;
|
||||
fix_edge.FixAddPCurve(edge, face, false, getValue(GV_PRECISION));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
const TopoDS_Face& face = TopoDS::Face(it.Value());
|
||||
|
||||
ShapeFix_Face sfs(TopoDS::Face(face));
|
||||
TopTools_DataMapOfShapeListOfShape wire_map;
|
||||
sfs.FixOrientation(wire_map);
|
||||
|
||||
TopoDS_Iterator jt(face, false);
|
||||
for (; jt.More(); jt.Next()) {
|
||||
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
|
||||
// tfk: @todo if wire_map contains w, I would assume wire_senses also contains w,
|
||||
// this is not the case in github issue #405.
|
||||
if (wire_map.IsBound(w) && wire_senses.IsBound(w)) {
|
||||
const TopTools_ListOfShape& shapes = wire_map.Find(w);
|
||||
TopTools_ListIteratorOfListOfShape kt(shapes);
|
||||
for (; kt.More(); kt.Next()) {
|
||||
// Apparently the wire got reversed, so register it with opposite orientation in the map
|
||||
wire_senses.Bind(kt.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it.Value() = sfs.Face();
|
||||
}
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
TopoDS_Face& face = TopoDS::Face(it.Value());
|
||||
|
||||
bool all_reversed = true;
|
||||
TopoDS_Iterator jt(face, false);
|
||||
for (; jt.More(); jt.Next()) {
|
||||
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
|
||||
if (!wire_senses.IsBound(w.Oriented(TopAbs_FORWARD)) || (w.Orientation() == wire_senses.Find(w.Oriented(TopAbs_FORWARD)))) {
|
||||
all_reversed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_reversed) {
|
||||
face.Reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (face_list.Extent() > 1) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
TopoDS_Face& face = TopoDS::Face(it.Value());
|
||||
builder.Add(compound, face);
|
||||
}
|
||||
result = compound;
|
||||
} else {
|
||||
result = face_list.First();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
|
||||
TopoDS_Wire wire;
|
||||
if ( ! convert_wire(l->OuterCurve(),wire) ) return false;
|
||||
if (!convert_wire(l->OuterCurve(), wire)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert_closed_wire(wire);
|
||||
|
||||
TopoDS_Face f;
|
||||
bool success = convert_wire_to_face(wire, f);
|
||||
if (success) face = f;
|
||||
if (success) {
|
||||
face = f;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) {
|
||||
TopoDS_Wire profile;
|
||||
if ( ! convert_wire(l->OuterCurve(),profile) ) return false;
|
||||
if (!convert_wire(l->OuterCurve(), profile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert_closed_wire(profile);
|
||||
|
||||
BRepBuilderAPI_MakeFace mf(profile);
|
||||
|
||||
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
|
||||
for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) {
|
||||
|
||||
for(IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++it) {
|
||||
TopoDS_Wire hole;
|
||||
if ( convert_wire(*it,hole) ) {
|
||||
if (convert_wire(*it, hole)) {
|
||||
assert_closed_wire(hole);
|
||||
mf.Add(hole);
|
||||
}
|
||||
}
|
||||
|
||||
ShapeFix_Shape sfs(mf.Face());
|
||||
sfs.Perform();
|
||||
face = TopoDS::Face(sfs.Shape());
|
||||
face = sfs.Shape();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS_Shape& face) {
|
||||
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords[8] = {-x,-y,x,-y,x,y,-x,y};
|
||||
return profile_helper(4,coords,0,0,0,trsf2d,face);
|
||||
}
|
||||
@@ -254,12 +489,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l,
|
||||
const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords[8] = {-x,-y, x,-y, x,y, -x,y};
|
||||
int fillets[4] = {0,1,2,3};
|
||||
double radii[4] = {r,r,r,r};
|
||||
@@ -278,7 +520,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
|
||||
const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -286,7 +528,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
|
||||
TopoDS_Face f2;
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords1[8] = {-x ,-y, x ,-y, x, y, -x, y };
|
||||
double coords2[8] = {-x+d,-y+d, x-d,-y+d, x-d,y-d, -x+d,y-d};
|
||||
double radii1[4] = {r1,r1,r1,r1};
|
||||
@@ -320,12 +569,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords[8] = {-x1,-y, x1,-y, dx+w-x1,y, dx-x1,y};
|
||||
return profile_helper(4,coords,0,0,0,trsf2d,face);
|
||||
}
|
||||
@@ -345,7 +601,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
|
||||
bool doFillet2 = doFillet1;
|
||||
double x2 = x1, dy2 = dy1, f2 = f1;
|
||||
|
||||
if (l->is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) {
|
||||
if (l->declaration().is(IfcSchema::IfcAsymmetricIShapeProfileDef::Class())) {
|
||||
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l;
|
||||
x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT);
|
||||
doFillet2 = assym->hasTopFlangeFilletRadius();
|
||||
@@ -358,12 +614,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords[24] = {-x1,-y, x1,-y, x1,-y+dy1, d1,-y+dy1, d1,y-dy2, x2,y-dy2, x2,y, -x2,y, -x2,y-dy2, -d1,y-dy2, -d1,-y+dy1, -x1,-y+dy1};
|
||||
int fillets[4] = {3,4,9,10};
|
||||
@@ -391,12 +653,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords[16] = {-dx,-y, x,-y, x,-y+dy, dx,-y+dy, dx,y, -x,y, -x,y-dy, -dx,y-dy};
|
||||
int fillets[4] = {2,3,6,7};
|
||||
@@ -418,12 +686,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y};
|
||||
int fillets[8] = {0,1,4,5,6,7,10,11};
|
||||
@@ -451,7 +725,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -483,7 +757,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
|
||||
const double det = a1*b2 - a2*b1;
|
||||
|
||||
if (ALMOST_THE_SAME(det, 0.)) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -492,7 +766,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y};
|
||||
int fillets[3] = {2,3,4};
|
||||
@@ -529,12 +809,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords[16] = {-x,-y, x,-y, x,-y+d2-dy2, -x+d1,-y+d2+dy1, -x+d1,y-d2-dy1, x,y-d2+dy2, x,y, -x,y};
|
||||
int fillets[4] = {2,3,4,5};
|
||||
@@ -557,7 +843,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
|
||||
const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -605,7 +891,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
|
||||
const double det = a1*b2 - a2*b1;
|
||||
|
||||
if (ALMOST_THE_SAME(det, 0.)) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -617,7 +903,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(l->Position(),trsf2d);
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
double coords[16] = {d1/2.-dx2,-y, xx,xy, x,y-d2+dy2, x,y, -x,y, -x,y-d2+dy2, -xx,xy, -d1/2.+dx2,-y};
|
||||
int fillets[6] = {0,1,2,5,6,7};
|
||||
@@ -628,17 +920,25 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
convert(l->Position(),trsf);
|
||||
gp_Trsf2d trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf2d);
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
|
||||
Handle(Geom_Circle) circle = new Geom_Circle(ax, r);
|
||||
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
w.Add(edge);
|
||||
|
||||
TopoDS_Face f;
|
||||
@@ -652,13 +952,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, Top
|
||||
const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( r == 0.0f || t == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
convert(l->Position(),trsf);
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
gp_Trsf2d trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf2d);
|
||||
|
||||
BRepBuilderAPI_MakeWire outer;
|
||||
Handle(Geom_Circle) outerCircle = new Geom_Circle(ax, r);
|
||||
@@ -681,20 +988,27 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_S
|
||||
double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool rotated = ry > rx;
|
||||
gp_Trsf2d trsf;
|
||||
convert(l->Position(),trsf);
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
gp_Ax2 ax = gp_Ax2();
|
||||
if (rotated) {
|
||||
ax.Rotate(ax.Axis(), M_PI / 2.);
|
||||
std::swap(rx, ry);
|
||||
}
|
||||
ax.Transform(trsf);
|
||||
ax.Transform(trsf2d);
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
Handle(Geom_Ellipse) ellipse = new Geom_Ellipse(ax, rx, ry);
|
||||
@@ -764,7 +1078,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles = l->Profiles();
|
||||
bool first = true;
|
||||
//bool first = true;
|
||||
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) {
|
||||
TopoDS_Face f;
|
||||
if (convert_face(*it, f)) {
|
||||
@@ -798,20 +1112,32 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_S
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) {
|
||||
gp_Pln pln;
|
||||
convert(l, pln);
|
||||
Handle_Geom_Surface surf = new Geom_Plane(pln);
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
face = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
|
||||
bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface& surf) {
|
||||
SHARED_PTR< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) {
|
||||
boost::shared_ptr< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
|
||||
std::vector<double> uknots = l->UKnots();
|
||||
std::vector<double> vknots = l->VKnots();
|
||||
std::vector<int> umults = l->UMultiplicities();
|
||||
std::vector<int> vmults = l->VMultiplicities();
|
||||
|
||||
TColgp_Array2OfPnt Poles (0, cps->size() - 1, 0, (*cps->begin()).size() - 1);
|
||||
TColStd_Array1OfReal UKnots(0, uknots.size() - 1);
|
||||
TColStd_Array1OfReal VKnots(0, vknots.size() - 1);
|
||||
TColStd_Array1OfInteger UMults(0, umults.size() - 1);
|
||||
TColStd_Array1OfInteger VMults(0, vmults.size() - 1);
|
||||
TColgp_Array2OfPnt Poles (0, (int)cps->size() - 1, 0, (int)(*cps->begin()).size() - 1);
|
||||
TColStd_Array1OfReal UKnots(0, (int)uknots.size() - 1);
|
||||
TColStd_Array1OfReal VKnots(0, (int)vknots.size() - 1);
|
||||
TColStd_Array1OfInteger UMults(0, (int)umults.size() - 1);
|
||||
TColStd_Array1OfInteger VMults(0, (int)vmults.size() - 1);
|
||||
Standard_Integer UDegree = l->UDegree();
|
||||
Standard_Integer VDegree = l->VDegree();
|
||||
|
||||
@@ -841,51 +1167,13 @@ bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface&
|
||||
for (std::vector<int>::const_iterator it = vmults.begin(); it != vmults.end(); ++it, ++i) {
|
||||
VMults(i) = *it;
|
||||
}
|
||||
surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
|
||||
return true;
|
||||
}
|
||||
Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
|
||||
|
||||
bool convert_surf(IfcSchema::IfcPlane* l, Handle_Geom_Surface& surf) {
|
||||
gp_Pln pln;
|
||||
convert(l, pln);
|
||||
surf = new Geom_Plane(pln);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedFace* l, TopoDS_Shape& face) {
|
||||
IfcSchema::IfcSurface* s = l->FaceSurface();
|
||||
Handle_Geom_Surface surf(0);
|
||||
if (s->is(IfcSchema::Type::IfcBSplineSurfaceWithKnots)) {
|
||||
convert_surf((IfcSchema::IfcBSplineSurfaceWithKnots*)s, surf);
|
||||
} else if (s->is(IfcSchema::Type::IfcPlane)) {
|
||||
convert_surf((IfcSchema::IfcPlane*)s, surf);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeFace mf(surf, Precision::Confusion());
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcLoop* loop = (*it)->Bound();
|
||||
TopoDS_Wire outer_wire;
|
||||
if (!convert_wire(loop, outer_wire)) return false;
|
||||
|
||||
TopoDS_Face temp = BRepBuilderAPI_MakeFace(surf, outer_wire);
|
||||
|
||||
if (BRepCheck_Face(temp).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
|
||||
outer_wire.Reverse();
|
||||
ShapeFix_Face fix(BRepBuilderAPI_MakeFace(surf, outer_wire).Face());
|
||||
fix.FixOrientation();
|
||||
fix.Perform();
|
||||
TopoDS_Face temp = fix.Face();
|
||||
TopExp_Explorer exp(temp, TopAbs_WIRE);
|
||||
outer_wire = TopoDS::Wire(exp.Current());
|
||||
}
|
||||
|
||||
mf.Add(outer_wire);
|
||||
}
|
||||
|
||||
face = mf.Face();
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
face = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+3531
-345
File diff suppressed because it is too large
Load Diff
+141
-24
@@ -77,6 +77,58 @@
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper functions (re)set gp_(G)Trsf(2d) forms explicitly to 'Identity'
|
||||
// so that it can be easily identified in the IfcMappedItem processing
|
||||
|
||||
// For axis placements detect equality early in order for the
|
||||
// relatively computionaly expensive gp_Trsf calculation to be skipped
|
||||
template <typename T>
|
||||
bool axis_equal(const T& a, const T& b, double tolerance);
|
||||
template <>
|
||||
bool axis_equal(const gp_Ax3& a, const gp_Ax3& b, double tolerance) {
|
||||
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
|
||||
// Note that the tolerance below is angular, above is linear. Since architectural
|
||||
// objects are about 1m'ish in scale, it should be somewhat equivalent. Besides,
|
||||
// this is mostly a filter for NULL or default values in the placements.
|
||||
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
|
||||
if (!a.XDirection().IsEqual(b.XDirection(), tolerance)) return false;
|
||||
if (!a.YDirection().IsEqual(b.YDirection(), tolerance)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool axis_equal(const gp_Ax2d& a, const gp_Ax2d& b, double tolerance) {
|
||||
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
|
||||
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T> struct dimension_count {};
|
||||
template <> struct dimension_count <gp_Trsf2d > { static const int n = 2; };
|
||||
template <> struct dimension_count <gp_GTrsf2d> { static const int n = 2; };
|
||||
template <> struct dimension_count < gp_Trsf > { static const int n = 3; };
|
||||
template <> struct dimension_count < gp_GTrsf > { static const int n = 3; };
|
||||
|
||||
template <typename T>
|
||||
bool is_identity(const T& t, double tolerance) {
|
||||
// Note the {1, n+1} range due to Open Cascade's 1-based indexing
|
||||
// Note the {1, n+2} range due to the translation part of the matrix
|
||||
for (int i = 1; i < dimension_count<T>::n + 2; ++i) {
|
||||
for (int j = 1; j < dimension_count<T>::n + 1; ++j) {
|
||||
const double iden_value = i == j ? 1. : 0.;
|
||||
const double trsf_value = t.Value(j, i);
|
||||
if (fabs(trsf_value - iden_value) > tolerance) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) {
|
||||
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
|
||||
std::vector<double> xyz = l->Coordinates();
|
||||
@@ -111,16 +163,43 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) {
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
|
||||
IfcGeom::Kernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
|
||||
gp_Ax3 ax3;
|
||||
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
|
||||
else ax3 = gp_Ax3(o,axis);
|
||||
trsf.SetTransformation(ax3, gp_Ax3(gp_Pnt(),gp_Dir(0,0,1),gp_Dir(1,0,0)));
|
||||
IN_CACHE(IfcAxis2Placement3D, l, gp_Trsf, trsf)
|
||||
|
||||
gp_Pnt o;
|
||||
gp_Dir axis(0, 0, 1);
|
||||
gp_Dir refDirection;
|
||||
|
||||
IfcGeom::Kernel::convert(l->Location(), o);
|
||||
const bool hasAxis = l->hasAxis();
|
||||
const bool hasRef = l->hasRefDirection();
|
||||
|
||||
if (hasAxis != hasRef) {
|
||||
Logger::Warning("Axis and RefDirection should be specified together", l);
|
||||
}
|
||||
|
||||
if (hasAxis) {
|
||||
IfcGeom::Kernel::convert(l->Axis(), axis);
|
||||
}
|
||||
|
||||
if (hasRef) {
|
||||
IfcGeom::Kernel::convert(l->RefDirection(), refDirection);
|
||||
} else {
|
||||
if (!axis.IsParallel(gp::DX(), 1.e-5)) {
|
||||
refDirection = gp::DX();
|
||||
} else {
|
||||
refDirection = gp::DZ();
|
||||
}
|
||||
gp_Vec Xvec = axis.Dot(refDirection) * axis;
|
||||
gp_Vec Xaxis = refDirection.XYZ() - Xvec.XYZ();
|
||||
refDirection = Xaxis;
|
||||
}
|
||||
|
||||
gp_Ax3 ax3(o, axis, refDirection);
|
||||
|
||||
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(ax3, gp::XOY());
|
||||
}
|
||||
|
||||
CACHE(IfcAxis2Placement3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
@@ -147,9 +226,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
|
||||
if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
|
||||
gp_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
|
||||
|
||||
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
}
|
||||
|
||||
if (l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.)) {
|
||||
trsf.SetScaleFactor(l->Scale());
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
@@ -183,7 +269,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
|
||||
}
|
||||
|
||||
trsf.Invert();
|
||||
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
|
||||
if ( l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.) ) trsf.SetScaleFactor(l->Scale());
|
||||
|
||||
if (is_identity(trsf, getValue(GV_PRECISION))) {
|
||||
trsf = gp_Trsf2d();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator2D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
@@ -211,6 +302,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
gtrsf.SetValue(3,3,scale3);
|
||||
gtrsf.PreMultiply(trsf);
|
||||
|
||||
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
|
||||
gtrsf = gp_GTrsf();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
@@ -247,6 +343,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
|
||||
gtrsf.SetValue(1,1,scale1);
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
gtrsf.Multiply(trsf);
|
||||
|
||||
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
|
||||
gtrsf = gp_GTrsf2d();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
@@ -274,33 +375,49 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d
|
||||
if ( l->hasRefDirection() )
|
||||
IfcGeom::Kernel::convert(l->RefDirection(),V);
|
||||
|
||||
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Dir2d(V.X(),V.Y()));
|
||||
trsf.SetTransformation(axis,gp_Ax2d());
|
||||
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()), gp_Dir2d(V.X(),V.Y()));
|
||||
|
||||
if (!axis_equal(axis, gp_Ax2d(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(axis, gp_Ax2d());
|
||||
}
|
||||
|
||||
CACHE(IfcAxis2Placement2D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
void IfcGeom::Kernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) {
|
||||
placement_rel_to = type;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf)
|
||||
if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
|
||||
if ( ! l->declaration().is(IfcSchema::IfcLocalPlacement::Class()) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
|
||||
return false;
|
||||
}
|
||||
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
|
||||
while (1) {
|
||||
for (;;) {
|
||||
gp_Trsf trsf2;
|
||||
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
|
||||
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
|
||||
if ( relplacement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class()) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
trsf.PreMultiply(trsf2);
|
||||
}
|
||||
if ( current->hasPlacementRelTo() ) {
|
||||
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
|
||||
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
|
||||
IfcSchema::IfcObjectPlacement* parent = current->PlacementRelTo();
|
||||
IfcSchema::IfcProduct::list::ptr parentPlaces = parent->PlacesObject();
|
||||
bool parentPlacesType = false;
|
||||
for ( IfcSchema::IfcProduct::list::it iter = parentPlaces->begin();
|
||||
iter != parentPlaces->end(); ++iter) {
|
||||
if ( (*iter)->declaration().is(*placement_rel_to) ) parentPlacesType = true;
|
||||
}
|
||||
|
||||
if ( parentPlacesType ) break;
|
||||
else if ( parent->declaration().is(IfcSchema::IfcLocalPlacement::Class()) )
|
||||
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
|
||||
else break;
|
||||
else break;
|
||||
} else break;
|
||||
}
|
||||
CACHE(IfcObjectPlacement,l,trsf)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,493 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
|
||||
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
|
||||
* *
|
||||
* IfcGeom::Representation::Triangulation is a class that represents a *
|
||||
* triangulated IfcShapeRepresentation. *
|
||||
* Triangulation.verts is a 1 dimensional vector of float defining the *
|
||||
* cartesian coordinates of the vertices of the triangulated shape in the *
|
||||
* format of [x1,y1,z1,..,xn,yn,zn] *
|
||||
* Triangulation.faces is a 1 dimensional vector of int containing the *
|
||||
* indices of the triangles referencing positions in Triangulation.verts *
|
||||
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
|
||||
* the visibility of the edges that span the faces in Triangulation.faces *
|
||||
* *
|
||||
* IfcGeom::Element represents the actual IfcBuildingElements. *
|
||||
* IfcGeomObject.name is the GUID of the element *
|
||||
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
|
||||
* IfcGeomObject.mesh is a pointer to an IfcMesh *
|
||||
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
|
||||
* orientation and translation of the mesh in relation to the world origin *
|
||||
* *
|
||||
* IfcGeom::Iterator::findContext() *
|
||||
* finds the most suitable representation contexts. Returns true iff *
|
||||
* at least a single representation will process successfully *
|
||||
* *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* returns a pointer to the current IfcGeom::Element *
|
||||
* *
|
||||
* IfcGeom::Iterator::next() *
|
||||
* returns true iff a following entity is available for a successive call to *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* *
|
||||
* IfcGeom::Iterator::progress() *
|
||||
* returns an int in [0..100] that indicates the overall progress *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMITERATOR_H
|
||||
#define IFCGEOMITERATOR_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P>
|
||||
class Iterator {
|
||||
private:
|
||||
Kernel kernel;
|
||||
IteratorSettings settings;
|
||||
|
||||
IfcParse::IfcFile* ifc_file;
|
||||
|
||||
// A container and iterator for IfcRepresentations
|
||||
IfcSchema::IfcRepresentation::list::ptr representations;
|
||||
IfcSchema::IfcRepresentation::list::it representation_iterator;
|
||||
|
||||
// The object is fetched beforehand to be sure that get() returns a valid element
|
||||
TriangulationElement<P>* current_triangulation;
|
||||
BRepElement<P>* current_shape_model;
|
||||
SerializedElement<P>* current_serialization;
|
||||
|
||||
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
|
||||
IfcSchema::IfcProduct::list::ptr ifcproducts;
|
||||
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
|
||||
|
||||
int done;
|
||||
int total;
|
||||
|
||||
std::string unit_name;
|
||||
// double?
|
||||
P unit_magnitude;
|
||||
|
||||
void initUnits() {
|
||||
IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType<IfcSchema::IfcProject>();
|
||||
if (projects->size() == 1) {
|
||||
IfcSchema::IfcProject* project = *projects->begin();
|
||||
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
|
||||
unit_name = length_unit.first;
|
||||
unit_magnitude = static_cast<P>(length_unit.second);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude;
|
||||
bool include_entities_in_processing;
|
||||
|
||||
void populate_set(const std::set<std::string>& include_or_ignore) {
|
||||
entities_to_include_or_exclude.clear();
|
||||
for (std::set<std::string>::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) {
|
||||
std::string uppercase_type = *it;
|
||||
for (std::string::iterator c = uppercase_type.begin(); c != uppercase_type.end(); ++c) {
|
||||
*c = toupper(*c);
|
||||
}
|
||||
IfcSchema::Type::Enum ty;
|
||||
try {
|
||||
ty = IfcSchema::Type::FromString(uppercase_type);
|
||||
} catch (const IfcParse::IfcException&) {
|
||||
std::stringstream ss;
|
||||
ss << "'" << *it << "' does not name a valid IFC entity";
|
||||
throw IfcParse::IfcException(ss.str());
|
||||
}
|
||||
entities_to_include_or_exclude.insert(ty);
|
||||
// TODO: Add child classes so that containment in set can be in O(log n)
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool findContext() {
|
||||
try {
|
||||
initUnits();
|
||||
} catch (...) {}
|
||||
|
||||
// Really this should only be 'Model', as per
|
||||
// the standard 'Design' is deprecated. So,
|
||||
// just for backwards compatibility:
|
||||
std::set<std::string> context_types;
|
||||
context_types.insert("model");
|
||||
context_types.insert("design");
|
||||
// DDS likes to output 'model view'
|
||||
context_types.insert("model view");
|
||||
|
||||
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
|
||||
bool any_precision_encountered = false;
|
||||
|
||||
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::it it;
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
|
||||
ifc_file->entitiesByType<IfcSchema::IfcGeometricRepresentationContext>();
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
|
||||
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (context->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
|
||||
// Continue, as the list of subcontexts will be considered
|
||||
// by the parent's context inverse attributes.
|
||||
continue;
|
||||
}
|
||||
if (context->hasContextType()) {
|
||||
std::string context_type_lc = context->ContextType();
|
||||
for (std::string::iterator c = context_type_lc.begin(); c != context_type_lc.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
}
|
||||
if (context_types.find(context_type_lc) != context_types.end()) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filtered_contexts->size() == 0) {
|
||||
filtered_contexts = contexts;
|
||||
}
|
||||
|
||||
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
|
||||
representations->push(context->RepresentationsInContext());
|
||||
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
|
||||
lowest_precision_encountered = context->Precision();
|
||||
any_precision_encountered = true;
|
||||
}
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
|
||||
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
|
||||
representations->push((*jt)->RepresentationsInContext());
|
||||
}
|
||||
// There is no need for full recursion as the following is governed by the schema:
|
||||
// WR31: The parent context shall not be another geometric representation sub context.
|
||||
}
|
||||
|
||||
if (any_precision_encountered) {
|
||||
// Some arbitrary factor that has proven to work better for the models in the set of test files.
|
||||
lowest_precision_encountered *= 10.;
|
||||
|
||||
lowest_precision_encountered *= unit_magnitude;
|
||||
if (lowest_precision_encountered < 1.e-7) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
|
||||
} else {
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
|
||||
}
|
||||
} else {
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
|
||||
}
|
||||
|
||||
if (representations->size() == 0) return false;
|
||||
|
||||
representation_iterator = representations->begin();
|
||||
ifcproducts.reset();
|
||||
|
||||
if (!create()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
total = representations->size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int progress() {
|
||||
return 100 * done / total;
|
||||
}
|
||||
|
||||
const std::string& getUnitName() {
|
||||
return unit_name;
|
||||
}
|
||||
|
||||
const P getUnitMagnitude() {
|
||||
return unit_magnitude;
|
||||
}
|
||||
|
||||
const std::string getLog() {
|
||||
return Logger::GetLog();
|
||||
}
|
||||
|
||||
IfcParse::IfcFile* getFile() {
|
||||
return ifc_file;
|
||||
}
|
||||
|
||||
void includeEntities(const std::set<std::string>& entities) {
|
||||
populate_set(entities);
|
||||
include_entities_in_processing = true;
|
||||
}
|
||||
|
||||
void excludeEntities(const std::set<std::string>& entities) {
|
||||
populate_set(entities);
|
||||
include_entities_in_processing = false;
|
||||
}
|
||||
|
||||
private:
|
||||
// Move to the next IfcRepresentation
|
||||
void _nextShape() {
|
||||
ifcproducts.reset();
|
||||
++ representation_iterator;
|
||||
++ done;
|
||||
}
|
||||
|
||||
BRepElement<P>* create_shape_model_for_next_entity() {
|
||||
while ( true ) {
|
||||
IfcSchema::IfcRepresentation* representation;
|
||||
|
||||
// Have we reached the end of our list of representations?
|
||||
if ( representation_iterator == representations->end() ) {
|
||||
representations.reset();
|
||||
return 0;
|
||||
}
|
||||
representation = *representation_iterator;
|
||||
|
||||
// Has the list of IfcProducts for this representation been initialized?
|
||||
if (!ifcproducts) {
|
||||
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
|
||||
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
|
||||
IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list);
|
||||
|
||||
for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
|
||||
if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
|
||||
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
|
||||
unfiltered_products->push(pds->ShapeOfProduct());
|
||||
} else {
|
||||
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
|
||||
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
|
||||
// It will be changed into an ABSTRACT supertype in future releases of IFC.
|
||||
|
||||
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
|
||||
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
|
||||
unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
|
||||
}
|
||||
|
||||
// Filter the products based on the set of entities being included or excluded for
|
||||
// processing. The set is iterated over te able to filter on subtypes.
|
||||
for ( IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it ) {
|
||||
bool found = false;
|
||||
for (std::set<IfcSchema::Type::Enum>::const_iterator jt = entities_to_include_or_exclude.begin(); jt != entities_to_include_or_exclude.end(); ++jt) {
|
||||
if ((*it)->is(*jt)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == include_entities_in_processing) {
|
||||
ifcproducts->push(*it);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Does this representation have any IfcProducts?
|
||||
if (!ifcproducts->size()) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
ifcproduct_iterator = ifcproducts->begin();
|
||||
}
|
||||
// Have we reached the end of our list of IfcProducts?
|
||||
if ( ifcproduct_iterator == ifcproducts->end() ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
|
||||
|
||||
BRepElement<P>* element = kernel.create_brep_for_representation_and_product<P>(settings, representation, product);
|
||||
|
||||
if ( !element ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool next() {
|
||||
// Free all possible representations of the current geometrical entity
|
||||
delete current_triangulation;
|
||||
current_triangulation = 0;
|
||||
delete current_serialization;
|
||||
current_serialization = 0;
|
||||
delete current_shape_model;
|
||||
current_shape_model = 0;
|
||||
|
||||
// Increment the iterator over the list of products using the current
|
||||
// shape representation
|
||||
if (ifcproducts) {
|
||||
++ifcproduct_iterator;
|
||||
}
|
||||
|
||||
return create();
|
||||
}
|
||||
|
||||
Element<P>* get() {
|
||||
// TODO: Test settings and throw
|
||||
if (current_triangulation) return current_triangulation;
|
||||
else if (current_serialization) return current_serialization;
|
||||
else if (current_shape_model) return current_shape_model;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
const Element<P>* getObject(int id) {
|
||||
|
||||
gp_Trsf trsf;
|
||||
int parent_id = -1;
|
||||
std::string instance_type, product_name, product_guid;
|
||||
|
||||
try {
|
||||
const IfcUtil::IfcBaseClass* ifc_entity = ifc_file->entityById(id);
|
||||
instance_type = IfcSchema::Type::ToString(ifc_entity->type());
|
||||
if ( ifc_entity->is(IfcSchema::Type::IfcProduct) ) {
|
||||
IfcSchema::IfcProduct* ifc_product = (IfcSchema::IfcProduct*)ifc_entity;
|
||||
|
||||
product_guid = ifc_product->GlobalId();
|
||||
product_name = ifc_product->hasName() ? ifc_product->Name() : "";
|
||||
|
||||
parent_id = -1;
|
||||
try {
|
||||
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->entity->id();
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
try {
|
||||
kernel.convert(ifc_product->ObjectPlacement(), trsf);
|
||||
} catch (...) {}
|
||||
}
|
||||
} catch(...) {}
|
||||
|
||||
ElementSettings element_settings(settings, unit_magnitude, instance_type);
|
||||
Element<P>* ifc_object = new Element<P>(element_settings, id, parent_id, product_name, instance_type, product_guid, trsf);
|
||||
|
||||
return ifc_object;
|
||||
}
|
||||
|
||||
bool create() {
|
||||
try {
|
||||
current_shape_model = create_shape_model_for_next_entity();
|
||||
} catch (...) {}
|
||||
if (!current_shape_model) return false;
|
||||
if (settings.use_brep_data()) {
|
||||
try {
|
||||
current_serialization = new SerializedElement<P>(*current_shape_model);
|
||||
} catch (...) {}
|
||||
return !!current_serialization;
|
||||
} else if (!settings.disable_triangulation()) {
|
||||
try {
|
||||
current_triangulation = new TriangulationElement<P>(*current_shape_model);
|
||||
} catch (...) {}
|
||||
return !!current_triangulation;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
private:
|
||||
void initialize() {
|
||||
current_triangulation = 0;
|
||||
current_shape_model = 0;
|
||||
current_serialization = 0;
|
||||
|
||||
// Upon initialisation, the (empty) set of entity names,
|
||||
// should be excluded, or no products would be processed.
|
||||
include_entities_in_processing = false;
|
||||
|
||||
unit_name = "METER";
|
||||
unit_magnitude = 1.f;
|
||||
|
||||
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1);
|
||||
kernel.setValue(IfcGeom::Kernel::GV_FORCE_CCW_FACE_ORIENTATION, settings.force_ccw_face_orientation() ? 1 : -1);
|
||||
}
|
||||
public:
|
||||
Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file)
|
||||
: settings(settings)
|
||||
, ifc_file(file)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, const std::string& filename)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
{
|
||||
ifc_file->Init(filename);
|
||||
initialize();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, void* data, int length)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
{
|
||||
ifc_file->Init(data, length);
|
||||
initialize();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, std::istream& filestream, int length)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
{
|
||||
ifc_file->Init(filestream, length);
|
||||
initialize();
|
||||
}
|
||||
|
||||
~Iterator() {
|
||||
// TODO: Correctly implement destructor for IfcFile
|
||||
delete ifc_file;
|
||||
|
||||
delete current_triangulation;
|
||||
current_triangulation = 0;
|
||||
delete current_serialization;
|
||||
current_serialization = 0;
|
||||
delete current_shape_model;
|
||||
current_shape_model = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "IfcGeomIteratorImplementation.h"
|
||||
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
template class MAKE_TYPE_NAME(IteratorImplementation_)<float, float>;
|
||||
template class MAKE_TYPE_NAME(IteratorImplementation_)<float, double>;
|
||||
template class MAKE_TYPE_NAME(IteratorImplementation_)<double, double>;
|
||||
}
|
||||
|
||||
#define MAKE_INIT_FN__(a, b) init_ ## a ## b
|
||||
#define MAKE_INIT_FN_(a, b) MAKE_INIT_FN__(a, b)
|
||||
#define MAKE_INIT_FN(t) MAKE_INIT_FN_(t, IfcSchema)
|
||||
|
||||
namespace {
|
||||
template <typename P, typename PP>
|
||||
struct MAKE_TYPE_NAME(factory_t) {
|
||||
IfcGeom::IteratorImplementation<P, PP>* operator()(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters) const {
|
||||
return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)<P, PP>(settings, file, filters);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename P, typename PP>
|
||||
void MAKE_INIT_FN(IteratorImplementation_)(IteratorFactoryImplementation<P, PP>* mapping) {
|
||||
static const std::string schema_name = STRINGIFY(IfcSchema);
|
||||
MAKE_TYPE_NAME(factory_t)<P, PP> factory;
|
||||
mapping->bind(schema_name, factory);
|
||||
}
|
||||
|
||||
template void MAKE_INIT_FN(IteratorImplementation_)<float, float>(IteratorFactoryImplementation<float, float>*);
|
||||
template void MAKE_INIT_FN(IteratorImplementation_)<float, double>(IteratorFactoryImplementation<float, double>*);
|
||||
template void MAKE_INIT_FN(IteratorImplementation_)<double, double>(IteratorFactoryImplementation<double, double>*);
|
||||
@@ -0,0 +1,743 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
|
||||
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
|
||||
* *
|
||||
* IfcGeom::Representation::Triangulation is a class that represents a *
|
||||
* triangulated IfcShapeRepresentation. *
|
||||
* Triangulation.verts is a 1 dimensional vector of float defining the *
|
||||
* cartesian coordinates of the vertices of the triangulated shape in the *
|
||||
* format of [x1,y1,z1,..,xn,yn,zn] *
|
||||
* Triangulation.faces is a 1 dimensional vector of int containing the *
|
||||
* indices of the triangles referencing positions in Triangulation.verts *
|
||||
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
|
||||
* the visibility of the edges that span the faces in Triangulation.faces *
|
||||
* *
|
||||
* IfcGeom::Element represents the actual IfcBuildingElements. *
|
||||
* IfcGeomObject.name is the GUID of the element *
|
||||
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
|
||||
* IfcGeomObject.mesh is a pointer to an IfcMesh *
|
||||
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
|
||||
* orientation and translation of the mesh in relation to the world origin *
|
||||
* *
|
||||
* IfcGeom::Iterator::initialize() *
|
||||
* finds the most suitable representation contexts. Returns true iff *
|
||||
* at least a single representation will process successfully *
|
||||
* *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* returns a pointer to the current IfcGeom::Element *
|
||||
* *
|
||||
* IfcGeom::Iterator::next() *
|
||||
* returns true iff a following entity is available for a successive call to *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* *
|
||||
* IfcGeom::Iterator::progress() *
|
||||
* returns an int in [0..100] that indicates the overall progress *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMITERATOR_H
|
||||
#define IFCGEOMITERATOR_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
|
||||
|
||||
// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P, typename PP>
|
||||
class MAKE_TYPE_NAME(IteratorImplementation_) : public IteratorImplementation<P, PP> {
|
||||
private:
|
||||
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)& operator=(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
|
||||
|
||||
MAKE_TYPE_NAME(Kernel) kernel;
|
||||
IteratorSettings settings;
|
||||
|
||||
IfcParse::IfcFile* ifc_file;
|
||||
|
||||
// A container and iterator for IfcRepresentations
|
||||
IfcSchema::IfcRepresentation::list::ptr representations;
|
||||
IfcSchema::IfcRepresentation::list::it representation_iterator;
|
||||
|
||||
// The object is fetched beforehand to be sure that get() returns a valid element
|
||||
TriangulationElement<P, PP>* current_triangulation;
|
||||
BRepElement<P, PP>* current_shape_model;
|
||||
SerializedElement<P, PP>* current_serialization;
|
||||
|
||||
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
|
||||
IfcSchema::IfcProduct::list::ptr ifcproducts;
|
||||
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
|
||||
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr ok_mapped_representations;
|
||||
|
||||
int done;
|
||||
int total;
|
||||
|
||||
std::string unit_name;
|
||||
double unit_magnitude;
|
||||
|
||||
gp_XYZ bounds_min_;
|
||||
gp_XYZ bounds_max_;
|
||||
|
||||
std::vector<filter_t> filters_;
|
||||
|
||||
struct filter_match
|
||||
{
|
||||
filter_match(IfcSchema::IfcProduct *prod) : product(prod) {}
|
||||
bool operator()(const filter_t& filter) const { return filter(product); }
|
||||
|
||||
IfcSchema::IfcProduct* product;
|
||||
};
|
||||
|
||||
void initUnits() {
|
||||
IfcSchema::IfcProject::list::ptr projects = ifc_file->instances_by_type<IfcSchema::IfcProject>();
|
||||
if (projects->size() == 1) {
|
||||
IfcSchema::IfcProject* project = *projects->begin();
|
||||
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
|
||||
unit_name = length_unit.first;
|
||||
unit_magnitude = length_unit.second;
|
||||
} else {
|
||||
Logger::Warning("A single IfcProject is expected (encountered " + boost::lexical_cast<std::string>(projects->size()) + "); unable to read unit information.");
|
||||
}
|
||||
}
|
||||
|
||||
/// @todo public/private sections all over the place: move all public to the beginning of the class
|
||||
public:
|
||||
typedef P Precision;
|
||||
typedef PP PlacementPrecision;
|
||||
|
||||
bool initialize() {
|
||||
try {
|
||||
initUnits();
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
std::set<std::string> allowed_context_types;
|
||||
allowed_context_types.insert("model");
|
||||
allowed_context_types.insert("plan");
|
||||
allowed_context_types.insert("notdefined");
|
||||
|
||||
std::set<std::string> context_types;
|
||||
if (!settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) {
|
||||
// Really this should only be 'Model', as per
|
||||
// the standard 'Design' is deprecated. So,
|
||||
// just for backwards compatibility:
|
||||
context_types.insert("model");
|
||||
context_types.insert("design");
|
||||
// Some earlier (?) versions DDS-CAD output their own ContextTypes
|
||||
context_types.insert("model view");
|
||||
context_types.insert("detail view");
|
||||
}
|
||||
if (settings.get(IteratorSettings::INCLUDE_CURVES)) {
|
||||
context_types.insert("plan");
|
||||
}
|
||||
|
||||
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
|
||||
bool any_precision_encountered = false;
|
||||
|
||||
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
|
||||
ok_mapped_representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::it it;
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
|
||||
ifc_file->instances_by_type<IfcSchema::IfcGeometricRepresentationContext>();
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
|
||||
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) {
|
||||
// Continue, as the list of subcontexts will be considered
|
||||
// by the parent's context inverse attributes.
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (context->hasContextType()) {
|
||||
std::string context_type = context->ContextType();
|
||||
boost::to_lower(context_type);
|
||||
|
||||
if (allowed_context_types.find(context_type) == allowed_context_types.end()) {
|
||||
Logger::Warning(std::string("ContextType '") + context->ContextType() + "' not allowed:", context);
|
||||
}
|
||||
if (context_types.find(context_type) != context_types.end()) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// In case no contexts are identified based on their ContextType, all contexts are
|
||||
// considered. Note that sub contexts are excluded as they are considered later on.
|
||||
if (filtered_contexts->size() == 0) {
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (!context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
|
||||
representations->push(context->RepresentationsInContext());
|
||||
try {
|
||||
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
|
||||
lowest_precision_encountered = context->Precision();
|
||||
any_precision_encountered = true;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
|
||||
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
|
||||
representations->push((*jt)->RepresentationsInContext());
|
||||
}
|
||||
// There is no need for full recursion as the following is governed by the schema:
|
||||
// WR31: The parent context shall not be another geometric representation sub context.
|
||||
}
|
||||
|
||||
if (any_precision_encountered) {
|
||||
// Some arbitrary factor that has proven to work better for the models in the set of test files.
|
||||
lowest_precision_encountered *= 10.;
|
||||
|
||||
lowest_precision_encountered *= unit_magnitude;
|
||||
if (lowest_precision_encountered < 1.e-7) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
|
||||
} else {
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
|
||||
}
|
||||
} else {
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
|
||||
}
|
||||
|
||||
if (representations->size() == 0) {
|
||||
Logger::Warning("No representations encountered in relevant contexts, using all");
|
||||
representations = ifc_file->instances_by_type<IfcSchema::IfcRepresentation>();
|
||||
}
|
||||
|
||||
if (representations->size() == 0) {
|
||||
Logger::Warning("No representations encountered, aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
representation_iterator = representations->begin();
|
||||
ifcproducts.reset();
|
||||
|
||||
if (!create()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
total = representations->size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Computes model's bounding box (bounds_min and bounds_max).
|
||||
/// @note Can take several minutes for large files.
|
||||
void compute_bounds()
|
||||
{
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
bounds_min_.SetCoord(i, std::numeric_limits<double>::infinity());
|
||||
bounds_max_.SetCoord(i, -std::numeric_limits<double>::infinity());
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct::list::ptr products = ifc_file->instances_by_type<IfcSchema::IfcProduct>();
|
||||
for (IfcSchema::IfcProduct::list::it iter = products->begin(); iter != products->end(); ++iter) {
|
||||
IfcSchema::IfcProduct* product = *iter;
|
||||
if (product->hasObjectPlacement()) {
|
||||
// Use a fresh trsf every time in order to prevent the result to be concatenated
|
||||
gp_Trsf trsf;
|
||||
bool success = false;
|
||||
|
||||
try {
|
||||
success = kernel.convert(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const gp_XYZ& pos = trsf.TranslationPart();
|
||||
bounds_min_.SetX(std::min(bounds_min_.X(), pos.X()));
|
||||
bounds_min_.SetY(std::min(bounds_min_.Y(), pos.Y()));
|
||||
bounds_min_.SetZ(std::min(bounds_min_.Z(), pos.Z()));
|
||||
bounds_max_.SetX(std::max(bounds_max_.X(), pos.X()));
|
||||
bounds_max_.SetY(std::max(bounds_max_.Y(), pos.Y()));
|
||||
bounds_max_.SetZ(std::max(bounds_max_.Z(), pos.Z()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int progress() const { return 100 * done / total; }
|
||||
|
||||
const std::string& getUnitName() const { return unit_name; }
|
||||
|
||||
/// @note Double always as per IFC specification.
|
||||
double getUnitMagnitude() const { return unit_magnitude; }
|
||||
|
||||
std::string getLog() const { return Logger::GetLog(); }
|
||||
|
||||
IfcParse::IfcFile* file() const { return ifc_file; }
|
||||
|
||||
const std::vector<IfcGeom::filter_t>& filters() const { return filters_; }
|
||||
std::vector<IfcGeom::filter_t>& filters() { return filters_; }
|
||||
|
||||
const gp_XYZ& bounds_min() const { return bounds_min_; }
|
||||
const gp_XYZ& bounds_max() const { return bounds_max_; }
|
||||
|
||||
private:
|
||||
// Move to the next IfcRepresentation
|
||||
void _nextShape() {
|
||||
// In order to conserve memory and reduce cache insertion times, the cache is
|
||||
// cleared after an arbitrary number of processed representations. This has been
|
||||
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
|
||||
static const int clear_interval = 64;
|
||||
if (done % clear_interval == clear_interval - 1) {
|
||||
kernel.purge_cache();
|
||||
}
|
||||
ifcproducts.reset();
|
||||
++ representation_iterator;
|
||||
++ done;
|
||||
}
|
||||
|
||||
bool geometry_reuse_ok_for_current_representation_;
|
||||
|
||||
bool reuse_ok_(const IfcSchema::IfcProduct::list::ptr& products) {
|
||||
// With world coords enabled, object transformations are directly applied to
|
||||
// the BRep. There is no way to re-use the geometry for multiple products.
|
||||
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<const IfcSchema::IfcMaterial*> associated_single_materials;
|
||||
|
||||
for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it) {
|
||||
IfcSchema::IfcProduct* product = *it;
|
||||
|
||||
if (!settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && kernel.find_openings(product)->size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings.get(IteratorSettings::APPLY_LAYERSETS)) {
|
||||
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
|
||||
for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin(); jt != associations->end(); ++jt) {
|
||||
IfcSchema::IfcRelAssociatesMaterial* assoc = (*jt)->as<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
if (assoc) {
|
||||
if (assoc->RelatingMaterial()->declaration().is(IfcSchema::IfcMaterialLayerSetUsage::Class())) {
|
||||
// TODO: Check whether single layer?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this can be a nullptr (!), but the fact that set size should be one still holds
|
||||
associated_single_materials.insert(kernel.get_single_material_association(product));
|
||||
if (associated_single_materials.size() > 1) return false;
|
||||
}
|
||||
|
||||
return associated_single_materials.size() == 1;
|
||||
}
|
||||
|
||||
BRepElement<P, PP>* create_shape_model_for_next_entity() {
|
||||
for (;;) {
|
||||
IfcSchema::IfcRepresentation* representation;
|
||||
|
||||
if ( representation_iterator == representations->end() ) {
|
||||
representations.reset();
|
||||
return 0; // reached the end of our list of representations
|
||||
}
|
||||
representation = *representation_iterator;
|
||||
|
||||
if (!ifcproducts) {
|
||||
// Init. the list of filtered IfcProducts for this representation
|
||||
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
|
||||
IfcSchema::IfcProduct::list::ptr unfiltered_products = kernel.products_represented_by(representation);
|
||||
// Include only the desired products for processing.
|
||||
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
|
||||
IfcSchema::IfcProduct* prod = *jt;
|
||||
if (boost::all(filters_, filter_match(prod))) {
|
||||
ifcproducts->push(prod);
|
||||
}
|
||||
}
|
||||
|
||||
if (ifcproducts->size() == 0) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
geometry_reuse_ok_for_current_representation_ = reuse_ok_(ifcproducts);
|
||||
|
||||
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
|
||||
|
||||
if (!geometry_reuse_ok_for_current_representation_ && maps->size() == 1) {
|
||||
// unfiltered_products contains products represented by this representation by means of mapped items.
|
||||
// For example because of openings applied to products, reuse might not be acceptable and then the
|
||||
// products will be processed by means of their immediate representation and not the mapped representation.
|
||||
|
||||
// IfcRepresentationMaps are also used for IfcTypeProducts, so an additional check is performed whether the map
|
||||
// is indeed used by IfcMappedItems.
|
||||
IfcSchema::IfcRepresentationMap* map = *maps->begin();
|
||||
if (map->MapUsage()->size() > 0) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this represenation has (or will be) processed as part its mapped representation
|
||||
bool representation_processed_as_mapped_item = false;
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = kernel.representation_mapped_to(representation);
|
||||
if (representation_mapped_to) {
|
||||
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && (
|
||||
ok_mapped_representations->contains(representation_mapped_to) || reuse_ok_(kernel.products_represented_by(representation_mapped_to)));
|
||||
}
|
||||
|
||||
if (representation_processed_as_mapped_item) {
|
||||
ok_mapped_representations->push(representation_mapped_to);
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
ifcproduct_iterator = ifcproducts->begin();
|
||||
}
|
||||
|
||||
// Have we reached the end of our list of IfcProducts?
|
||||
if ( ifcproduct_iterator == ifcproducts->end() ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
|
||||
Logger::SetProduct(product);
|
||||
|
||||
BRepElement<P, PP>* element;
|
||||
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) {
|
||||
element = kernel.create_brep_for_representation_and_product<P, PP>(settings, representation, product);
|
||||
} else {
|
||||
element = kernel.create_brep_for_processed_representation(settings, representation, product, current_shape_model);
|
||||
}
|
||||
|
||||
Logger::SetProduct(boost::none);
|
||||
|
||||
if (!element) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
void free_shapes() {
|
||||
// Free all possible representations of the current geometrical entity
|
||||
delete current_triangulation;
|
||||
current_triangulation = 0;
|
||||
delete current_serialization;
|
||||
current_serialization = 0;
|
||||
delete current_shape_model;
|
||||
current_shape_model = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
/// Returns what would be the product for the next shape representation
|
||||
/// @todo Double-check and test the impl.
|
||||
//IfcSchema::IfcProduct* peek_next() const
|
||||
//{
|
||||
// if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){
|
||||
// return *(ifcproduct_iterator + 1);
|
||||
// } else {
|
||||
// return 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
/// @todo Would this be as simple as the following code?
|
||||
//void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } }
|
||||
|
||||
/// Moves to the next shape representation, create its geometry, and returns the associated product.
|
||||
/// Use get() to retrieve the created geometry.
|
||||
IfcUtil::IfcBaseClass* next() {
|
||||
// Increment the iterator over the list of products using the current
|
||||
// shape representation
|
||||
if (ifcproducts) {
|
||||
++ifcproduct_iterator;
|
||||
}
|
||||
|
||||
return create();
|
||||
}
|
||||
|
||||
/// Gets the representation of the current geometrical entity.
|
||||
Element<P, PP>* get()
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
Element<P, PP>* ret = 0;
|
||||
if (current_triangulation) { ret = current_triangulation; }
|
||||
else if (current_serialization) { ret = current_serialization; }
|
||||
else if (current_shape_model) { ret = current_shape_model; }
|
||||
|
||||
// If we want to organize the element considering their hierarchy
|
||||
if (settings.get(IteratorSettings::SEARCH_FLOOR))
|
||||
{
|
||||
// We are going to build a vector with the element parents.
|
||||
// First, create the parent vector
|
||||
std::vector<const IfcGeom::Element<P, PP>*> parents;
|
||||
|
||||
// if the element has a parent
|
||||
if (ret->parent_id() != -1)
|
||||
{
|
||||
const IfcGeom::Element<P, PP>* parent_object = NULL;
|
||||
bool hasParent = true;
|
||||
|
||||
// get the parent
|
||||
try {
|
||||
parent_object = get_object(ret->parent_id());
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
hasParent = false;
|
||||
}
|
||||
|
||||
// Add the previously found parent to the vector
|
||||
if (hasParent) parents.insert(parents.begin(), parent_object);
|
||||
|
||||
// We need to find all the parents
|
||||
while (parent_object != NULL && hasParent && parent_object->parent_id() != -1)
|
||||
{
|
||||
// Find the next parent
|
||||
try {
|
||||
parent_object = get_object(parent_object->parent_id());
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
hasParent = false;
|
||||
}
|
||||
|
||||
// Add the previously found parent to the vector
|
||||
if (hasParent) parents.insert(parents.begin(), parent_object);
|
||||
|
||||
hasParent = hasParent && parent_object->parent_id() != -1;
|
||||
}
|
||||
|
||||
// when done push the parent list in the Element object
|
||||
ret->SetParents(parents);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Gets the native (Open Cascade) representation of the current geometrical entity.
|
||||
BRepElement<P, PP>* get_native()
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
return current_shape_model;
|
||||
}
|
||||
|
||||
const Element<P, PP>* get_object(int id) {
|
||||
gp_Trsf trsf;
|
||||
int parent_id = -1;
|
||||
std::string instance_type, product_name, product_guid;
|
||||
IfcSchema::IfcProduct* ifc_product = 0;
|
||||
|
||||
try {
|
||||
IfcUtil::IfcBaseClass* ifc_entity = ifc_file->instance_by_id(id);
|
||||
instance_type = ifc_entity->declaration().name();
|
||||
|
||||
if (ifc_entity->declaration().is(IfcSchema::IfcRoot::Class())) {
|
||||
IfcSchema::IfcRoot* ifc_root = ifc_entity->as<IfcSchema::IfcRoot>();
|
||||
product_guid = ifc_root->GlobalId();
|
||||
product_name = ifc_root->hasName() ? ifc_root->Name() : "";
|
||||
}
|
||||
|
||||
if (ifc_entity->declaration().is(IfcSchema::IfcProduct::Class())) {
|
||||
ifc_product = ifc_entity->as<IfcSchema::IfcProduct>();
|
||||
parent_id = -1;
|
||||
try {
|
||||
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product)->template as<IfcSchema::IfcObjectDefinition>();
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to find decomposing entity");
|
||||
}
|
||||
|
||||
try {
|
||||
kernel.convert(ifc_product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Error(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Error("Unknown error returning product");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error returning product");
|
||||
}
|
||||
|
||||
ElementSettings element_settings(settings, unit_magnitude, instance_type);
|
||||
|
||||
Element<P, PP>* ifc_object = new Element<P, PP>(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf, ifc_product);
|
||||
return ifc_object;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* create() {
|
||||
IfcGeom::BRepElement<P, PP>* next_shape_model = 0;
|
||||
IfcGeom::SerializedElement<P, PP>* next_serialization = 0;
|
||||
IfcGeom::TriangulationElement<P, PP>* next_triangulation = 0;
|
||||
|
||||
try {
|
||||
next_shape_model = create_shape_model_for_next_entity();
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Error(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Error("Unknown error creating geometry");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error creating geometry");
|
||||
}
|
||||
|
||||
if (next_shape_model) {
|
||||
if (settings.get(IteratorSettings::USE_BREP_DATA)) {
|
||||
try {
|
||||
next_serialization = new SerializedElement<P, PP>(*next_shape_model);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
|
||||
}
|
||||
} else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) {
|
||||
try {
|
||||
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) {
|
||||
next_triangulation = new TriangulationElement<P, PP>(*next_shape_model);
|
||||
} else {
|
||||
next_triangulation = new TriangulationElement<P, PP>(*next_shape_model, current_triangulation->geometry_pointer());
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_shapes();
|
||||
|
||||
current_shape_model = next_shape_model;
|
||||
current_serialization = next_serialization;
|
||||
current_triangulation = next_triangulation;
|
||||
|
||||
return next_shape_model ? next_shape_model->product() : 0;
|
||||
}
|
||||
private:
|
||||
void _initialize() {
|
||||
current_triangulation = 0;
|
||||
current_shape_model = 0;
|
||||
current_serialization = 0;
|
||||
|
||||
unit_name = "METER";
|
||||
unit_magnitude = 1.f;
|
||||
|
||||
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(IteratorSettings::SEW_SHELLS) ? std::numeric_limits<double>::infinity() : -1);
|
||||
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES)
|
||||
? (settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
|
||||
if (settings.get(IteratorSettings::BUILDING_LOCAL_PLACEMENT)) {
|
||||
if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "building-local-placement takes precedence over site-local-placement");
|
||||
}
|
||||
kernel.set_conversion_placement_rel_to(&IfcSchema::IfcBuilding::Class());
|
||||
} else if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) {
|
||||
kernel.set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class());
|
||||
}
|
||||
}
|
||||
|
||||
bool owns_ifc_file;
|
||||
public:
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters)
|
||||
: settings(settings)
|
||||
, ifc_file(file)
|
||||
, filters_(filters)
|
||||
, owns_ifc_file(false)
|
||||
{
|
||||
_initialize();
|
||||
}
|
||||
|
||||
~MAKE_TYPE_NAME(IteratorImplementation_)() {
|
||||
if (owns_ifc_file) {
|
||||
delete ifc_file;
|
||||
}
|
||||
|
||||
free_shapes();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -20,153 +20,140 @@
|
||||
#ifndef IFCGEOMITERATORSETTINGS_H
|
||||
#define IFCGEOMITERATORSETTINGS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace IfcGeom
|
||||
{
|
||||
class IFC_GEOM_API IteratorSettings
|
||||
{
|
||||
public:
|
||||
/// Enumeration of setting identifiers. These settings define the
|
||||
/// behaviour of various aspects of IfcOpenShell.
|
||||
enum Setting
|
||||
{
|
||||
/// Specifies whether vertices are welded, meaning that the coordinates
|
||||
/// vector will only contain unique xyz-triplets. This results in a
|
||||
/// manifold mesh which is useful for modelling applications, but might
|
||||
/// result in unwanted shading artifacts in rendering applications.
|
||||
WELD_VERTICES = 1,
|
||||
/// Specifies whether to apply the local placements of building elements
|
||||
/// directly to the coordinates of the representation mesh rather than
|
||||
/// to represent the local placement in the 4x3 matrix, which will in that
|
||||
/// case be the identity matrix.
|
||||
USE_WORLD_COORDS = 1 << 1,
|
||||
/// Internally IfcOpenShell measures everything in meters. This settings
|
||||
/// specifies whether to convert IfcGeomObjects back to the units in which
|
||||
/// the geometry in the IFC file is specified.
|
||||
CONVERT_BACK_UNITS = 1 << 2,
|
||||
/// Specifies whether to use the Open Cascade BREP format for representation
|
||||
/// items rather than to create triangle meshes. This is useful is IfcOpenShell
|
||||
/// is used as a library in an application that is also built on Open Cascade.
|
||||
USE_BREP_DATA = 1 << 3,
|
||||
/// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
|
||||
/// TopoDS_Shells or whether to keep them as a loose collection of faces.
|
||||
SEW_SHELLS = 1 << 4,
|
||||
/// Specifies whether to compose IfcOpeningElements into a single compound
|
||||
/// in order to speed up the processing of opening subtractions.
|
||||
FASTER_BOOLEANS = 1 << 5,
|
||||
/// Disables the subtraction of IfcOpeningElement representations from
|
||||
/// the related building element representations.
|
||||
DISABLE_OPENING_SUBTRACTIONS = 1 << 6,
|
||||
/// Disables the triangulation of the topological representations. Useful if
|
||||
/// the client application understands Open Cascade's native format.
|
||||
DISABLE_TRIANGULATION = 1 << 7,
|
||||
/// Applies default materials to entity instances without a surface style.
|
||||
APPLY_DEFAULT_MATERIALS = 1 << 8,
|
||||
/// Specifies whether to include subtypes of IfcCurve.
|
||||
INCLUDE_CURVES = 1 << 9,
|
||||
/// Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface.
|
||||
EXCLUDE_SOLIDS_AND_SURFACES = 1 << 10,
|
||||
/// Disables computation of normals. Saves time and file size and is useful
|
||||
/// in instances where you're going to recompute normals for the exported
|
||||
/// model in other modelling application in any case.
|
||||
NO_NORMALS = 1 << 11,
|
||||
/// Generates UVs by using simple box projection. Requires normals.
|
||||
/// Applicable for OBJ and DAE output.
|
||||
GENERATE_UVS = 1 << 12,
|
||||
/// Specifies whether to slice representations according to associated IfcLayerSets.
|
||||
APPLY_LAYERSETS = 1 << 13,
|
||||
/// Search for a parent of type IfcBuildingStorey for each representation
|
||||
SEARCH_FLOOR = 1 << 14,
|
||||
///
|
||||
SITE_LOCAL_PLACEMENT = 1 << 15,
|
||||
///
|
||||
BUILDING_LOCAL_PLACEMENT = 1 << 16,
|
||||
///
|
||||
VALIDATE_QUANTITIES = 1 << 17,
|
||||
/// Number of different setting flags.
|
||||
NUM_SETTINGS = 17
|
||||
};
|
||||
/// Used to store logical OR combination of setting flags.
|
||||
typedef unsigned SettingField;
|
||||
|
||||
class IteratorSettings {
|
||||
public:
|
||||
// Enumeration of setting identifiers. These settings define the
|
||||
// behaviour of various aspects of IfcOpenShell.
|
||||
IteratorSettings()
|
||||
: settings_(WELD_VERTICES) // OR options that default to true here
|
||||
, deflection_tolerance_(1.e-3)
|
||||
{
|
||||
}
|
||||
|
||||
// Specifies whether vertices are welded, meaning that the coordinates
|
||||
// vector will only contain unique xyz-triplets. This results in a
|
||||
// manifold mesh which is useful for modelling applications, but might
|
||||
// result in unwanted shading artifacts in rendering applications.
|
||||
static const int WELD_VERTICES = 1;
|
||||
// Specifies whether to apply the local placements of building elements
|
||||
// directly to the coordinates of the representation mesh rather than
|
||||
// to represent the local placement in the 4x3 matrix, which will in that
|
||||
// case be the identity matrix.
|
||||
static const int USE_WORLD_COORDS = 2;
|
||||
// Internally IfcOpenShell measures everything in meters. This settings
|
||||
// specifies whether to convert IfcGeomObjects back to the units in which
|
||||
// the geometry in the IFC file is specified.
|
||||
static const int CONVERT_BACK_UNITS = 3;
|
||||
// Specifies whether to use the Open Cascade BREP format for representation
|
||||
// items rather than to create triangle meshes. This is useful is IfcOpenShell
|
||||
// is used as a library in an application that is also built on Open Cascade.
|
||||
static const int USE_BREP_DATA = 4;
|
||||
// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
|
||||
// TopoDS_Shells or whether to keep them as a loose collection of faces.
|
||||
static const int SEW_SHELLS = 5;
|
||||
// Specifies whether to compose IfcOpeningElements into a single compound
|
||||
// in order to speed up the processing of opening subtractions.
|
||||
static const int FASTER_BOOLEANS = 6;
|
||||
// By default singular faces have no explicitly defined orientation, to
|
||||
// force faces to be defined CounterClockWise set this to true.
|
||||
static const int FORCE_CCW_FACE_ORIENTATION = 7;
|
||||
// Disables the subtraction of IfcOpeningElement representations from
|
||||
// the related building element representations.
|
||||
static const int DISABLE_OPENING_SUBTRACTIONS = 8;
|
||||
// Disables the triangulation of the topological representations. Useful if
|
||||
// the client application understands Open Cascade's native format.
|
||||
static const int DISABLE_TRIANGULATION = 9;
|
||||
// Applies default materials to entity instances without a surface style.
|
||||
static const int APPLY_DEFAULT_MATERIALS = 10;
|
||||
/// Note that this is independent of the IFC length unit, one millimeter by default.
|
||||
double deflection_tolerance() const { return deflection_tolerance_; }
|
||||
|
||||
// End of settings enumeration.
|
||||
void set_deflection_tolerance(double value)
|
||||
{
|
||||
/// @todo Using deflection tolerance of 1e-6 or smaller hangs the conversion, research more in-depth.
|
||||
/// This bug can be reproduced e.g. with the Duplex model that can be found from http://www.nibs.org/?page=bsa_commonbimfiles#project1
|
||||
deflection_tolerance_ = value;
|
||||
if (deflection_tolerance_ <= 1e-6) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Deflection tolerance cannot be set to <= 1e-6; using the default value 1e-3");
|
||||
deflection_tolerance_ = 1e-3;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _force_ccw_face_orientation, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials;
|
||||
double _deflection_tolerance;
|
||||
public:
|
||||
IteratorSettings()
|
||||
: _weld_vertices(true)
|
||||
, _use_world_coords(false)
|
||||
, _convert_back_units(false)
|
||||
, _use_brep_data(false)
|
||||
, _sew_shells(false)
|
||||
, _faster_booleans(false)
|
||||
, _force_ccw_face_orientation(false)
|
||||
, _disable_opening_subtractions(false)
|
||||
, _disable_triangulation(false)
|
||||
, _apply_default_materials(false)
|
||||
// TODO: Make deflection tolerance into a command line argument
|
||||
// For now, stick to one millimeter. Note that this is independent of the IFC length unit.
|
||||
, _deflection_tolerance(1.e-3)
|
||||
{}
|
||||
/// Get boolean value for a single settings or for a combination of settings.
|
||||
bool get(SettingField setting) const
|
||||
{
|
||||
/// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
|
||||
return (settings_ & setting) != 0;
|
||||
}
|
||||
|
||||
const bool& weld_vertices() const { return _weld_vertices; }
|
||||
bool& weld_vertices() { return _weld_vertices; }
|
||||
const bool& use_world_coords() const { return _use_world_coords; }
|
||||
bool& use_world_coords() { return _use_world_coords; }
|
||||
const bool& convert_back_units() const { return _convert_back_units; }
|
||||
bool& convert_back_units() { return _convert_back_units; }
|
||||
const bool& use_brep_data() const { return _use_brep_data; }
|
||||
bool& use_brep_data() { return _use_brep_data; }
|
||||
const bool& sew_shells() const { return _sew_shells; }
|
||||
bool& sew_shells() { return _sew_shells; }
|
||||
const bool& faster_booleans() const { return _faster_booleans; }
|
||||
bool& faster_booleans() { return _faster_booleans; }
|
||||
const bool& force_ccw_face_orientation() const { return _force_ccw_face_orientation; }
|
||||
bool& force_ccw_face_orientation() { return _force_ccw_face_orientation; }
|
||||
const bool& disable_opening_subtractions() const { return _disable_opening_subtractions; }
|
||||
bool& disable_opening_subtractions() { return _disable_opening_subtractions; }
|
||||
const bool& disable_triangulation() const { return _disable_triangulation; }
|
||||
bool& disable_triangulation() { return _disable_triangulation; }
|
||||
const bool& apply_default_materials() const { return _apply_default_materials; }
|
||||
bool& apply_default_materials() { return _apply_default_materials; }
|
||||
|
||||
const double& deflection_tolerance() const { return _deflection_tolerance; }
|
||||
double& deflection_tolerance() { return _deflection_tolerance; }
|
||||
|
||||
void set(int setting, bool value) {
|
||||
switch (setting) {
|
||||
case USE_WORLD_COORDS:
|
||||
_use_world_coords = value;
|
||||
break;
|
||||
case WELD_VERTICES:
|
||||
_weld_vertices = value;
|
||||
break;
|
||||
case CONVERT_BACK_UNITS:
|
||||
_convert_back_units = value;
|
||||
break;
|
||||
case USE_BREP_DATA:
|
||||
_use_brep_data = value;
|
||||
break;
|
||||
case FASTER_BOOLEANS:
|
||||
_faster_booleans = value;
|
||||
break;
|
||||
case SEW_SHELLS:
|
||||
_sew_shells = value;
|
||||
break;
|
||||
case FORCE_CCW_FACE_ORIENTATION:
|
||||
_force_ccw_face_orientation = value;
|
||||
break;
|
||||
case DISABLE_OPENING_SUBTRACTIONS:
|
||||
_disable_opening_subtractions = value;
|
||||
break;
|
||||
case DISABLE_TRIANGULATION:
|
||||
_disable_triangulation = value;
|
||||
break;
|
||||
case APPLY_DEFAULT_MATERIALS:
|
||||
_apply_default_materials = value;
|
||||
break;
|
||||
default: throw IfcParse::IfcException("Invalid IteratorSetting");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ElementSettings : public IteratorSettings {
|
||||
private:
|
||||
double _unit_magnitude;
|
||||
std::string _element_type;
|
||||
public:
|
||||
ElementSettings(const IteratorSettings& settings,
|
||||
double unit_magnitude,
|
||||
const std::string& element_type)
|
||||
: IteratorSettings(settings)
|
||||
, _unit_magnitude(unit_magnitude)
|
||||
, _element_type(element_type)
|
||||
{}
|
||||
/// Set boolean value for a single settings or for a combination of settings.
|
||||
void set(SettingField setting, bool value)
|
||||
{
|
||||
/// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
|
||||
if (value) {
|
||||
settings_ |= setting;
|
||||
} else {
|
||||
settings_ &= ~setting;
|
||||
}
|
||||
}
|
||||
|
||||
const double& unit_magnitude() const { return _unit_magnitude; }
|
||||
const std::string& element_type() const { return _element_type; }
|
||||
};
|
||||
protected:
|
||||
SettingField settings_;
|
||||
double deflection_tolerance_;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API ElementSettings : public IteratorSettings
|
||||
{
|
||||
public:
|
||||
ElementSettings(const IteratorSettings& settings,
|
||||
double unit_magnitude,
|
||||
const std::string& element_type)
|
||||
: IteratorSettings(settings)
|
||||
, unit_magnitude_(unit_magnitude)
|
||||
, element_type_(element_type)
|
||||
{
|
||||
}
|
||||
|
||||
double unit_magnitude() const { return unit_magnitude_; }
|
||||
const std::string& element_type() const { return element_type_; }
|
||||
|
||||
private:
|
||||
double unit_magnitude_;
|
||||
std::string element_type_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -21,56 +21,65 @@
|
||||
|
||||
#include "IfcGeom.h"
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>& rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
rgb[2] = colour->Blue();
|
||||
namespace {
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
rgb[2] = colour->Blue();
|
||||
}
|
||||
return colour != 0;
|
||||
}
|
||||
return colour != 0;
|
||||
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
|
||||
if (factor != 0) {
|
||||
const double f = *factor;
|
||||
rgb[0] = rgb[1] = rgb[2] = f;
|
||||
}
|
||||
return factor != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcColourRgb::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, std::tr1::array<double, 3>& rgb) {
|
||||
if (factor != 0) {
|
||||
const double f = *factor;
|
||||
rgb[0] = rgb[1] = rgb[2] = f;
|
||||
}
|
||||
return factor != 0;
|
||||
}
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, std::tr1::array<double, 3>& rgb) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcColourRgb)) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
|
||||
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> shading_styles = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item);
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_styles) {
|
||||
if (shading_styles.second == 0) {
|
||||
return 0;
|
||||
}
|
||||
int surface_style_id = shading_styles.first->entity->id();
|
||||
std::map<int,SurfaceStyle>::const_iterator it = cache.Style.find(surface_style_id);
|
||||
if (it != cache.Style.end()) {
|
||||
int surface_style_id = shading_styles.first->data().id();
|
||||
std::map<int,SurfaceStyle>::const_iterator it = style_cache.find(surface_style_id);
|
||||
if (it != style_cache.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
SurfaceStyle surface_style;
|
||||
if (shading_styles.first->hasName()) {
|
||||
surface_style = SurfaceStyle(surface_style_id, shading_styles.first->Name());
|
||||
|
||||
IfcSchema::IfcSurfaceStyle* style = shading_styles.first->as<IfcSchema::IfcSurfaceStyle>();
|
||||
IfcSchema::IfcSurfaceStyleShading* shading = shading_styles.second->as<IfcSchema::IfcSurfaceStyleShading>();
|
||||
|
||||
if (style->hasName()) {
|
||||
surface_style = SurfaceStyle(surface_style_id, style->Name());
|
||||
} else {
|
||||
surface_style = SurfaceStyle(surface_style_id);
|
||||
}
|
||||
std::tr1::array<double, 3> rgb;
|
||||
if (process_colour(shading_styles.second->SurfaceColour(), rgb)) {
|
||||
double rgb[3];
|
||||
if (process_colour(shading->SurfaceColour(), rgb)) {
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (shading_styles.second->is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
|
||||
if (shading_styles.second->declaration().is(IfcSchema::IfcSurfaceStyleRendering::Class())) {
|
||||
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
|
||||
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
|
||||
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1,1,1));
|
||||
@@ -87,12 +96,12 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
|
||||
}
|
||||
if (rendering_style->hasSpecularHighlight()) {
|
||||
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
|
||||
if (highlight->is(IfcSchema::Type::IfcSpecularRoughness)) {
|
||||
if (highlight->declaration().is(IfcSchema::IfcSpecularRoughness::Class())) {
|
||||
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
|
||||
if (roughness >= 1e-9) {
|
||||
surface_style.Specularity().reset(1.0 / roughness);
|
||||
}
|
||||
} else if (highlight->is(IfcSchema::Type::IfcSpecularExponent)) {
|
||||
} else if (highlight->declaration().is(IfcSchema::IfcSpecularExponent::Class())) {
|
||||
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
|
||||
}
|
||||
}
|
||||
@@ -104,59 +113,28 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
|
||||
surface_style.Transparency().reset(d);
|
||||
}
|
||||
}
|
||||
return &(cache.Style[surface_style_id] = surface_style);
|
||||
return &(style_cache[surface_style_id] = surface_style);
|
||||
}
|
||||
|
||||
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
|
||||
static IfcGeom::SurfaceStyle default_material;
|
||||
static bool default_materials_initialized = false;
|
||||
|
||||
void InitDefaultMaterials() {
|
||||
default_materials.insert(std::make_pair("IfcSite", IfcGeom::SurfaceStyle("IfcSite")));
|
||||
default_materials["IfcSite" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.65));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcSlab", IfcGeom::SurfaceStyle("IfcSlab")));
|
||||
default_materials["IfcSlab" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.4 , 0.4, 0.4 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWallStandardCase", IfcGeom::SurfaceStyle("IfcWallStandardCase")));
|
||||
default_materials["IfcWallStandardCase"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9 , 0.9, 0.9 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWall", IfcGeom::SurfaceStyle("IfcWall")));
|
||||
default_materials["IfcWall" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9 , 0.9, 0.9 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWindow", IfcGeom::SurfaceStyle("IfcWindow")));
|
||||
default_materials["IfcWindow" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.75));
|
||||
default_materials["IfcWindow" ].Transparency().reset(0.3);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcDoor", IfcGeom::SurfaceStyle("IfcDoor")));
|
||||
default_materials["IfcDoor" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.55, 0.3, 0.15));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcBeam", IfcGeom::SurfaceStyle("IfcBeam")));
|
||||
default_materials["IfcBeam" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.7, 0.7 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcRailing", IfcGeom::SurfaceStyle("IfcRailing")));
|
||||
default_materials["IfcRailing" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcMember", IfcGeom::SurfaceStyle("IfcMember")));
|
||||
default_materials["IfcMember" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcPlate", IfcGeom::SurfaceStyle("IfcPlate")));
|
||||
default_materials["IfcPlate" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.8 , 0.8, 0.8 ));
|
||||
|
||||
default_material = IfcGeom::SurfaceStyle("DefaultMaterial");
|
||||
default_material.Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.7, 0.7, 0.7));
|
||||
|
||||
default_materials_initialized = true;
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
|
||||
if (!default_materials_initialized) InitDefaultMaterials();
|
||||
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
|
||||
if (it == default_materials.end()) {
|
||||
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
|
||||
default_materials[s].Diffuse().reset(*default_material.Diffuse());
|
||||
it = default_materials.find(s);
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcMaterial* material) {
|
||||
IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation();
|
||||
for (IfcSchema::IfcMaterialDefinitionRepresentation::list::it jt = defs->begin(); jt != defs->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = (*jt)->Representations();
|
||||
IfcSchema::IfcStyledItem::list::ptr styles(new IfcSchema::IfcStyledItem::list);
|
||||
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
|
||||
styles->push((**it).Items()->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) {
|
||||
const std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> ss = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(*it);
|
||||
if (ss.second) {
|
||||
return internalize_surface_style(ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
const IfcGeom::SurfaceStyle& surface_style = it->second;
|
||||
return &surface_style;
|
||||
IfcGeom::SurfaceStyle material_style = IfcGeom::SurfaceStyle(material->data().id(), material->Name());
|
||||
return &(style_cache[material->data().id()] = material_style);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#include <BRep_Builder.hxx>
|
||||
|
||||
#include <TopoDS_Compound.hxx>
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
@@ -30,30 +32,220 @@
|
||||
|
||||
IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
|
||||
: Representation(brep.settings())
|
||||
, _id(brep.getId())
|
||||
, id_(brep.id())
|
||||
{
|
||||
TopoDS_Compound compound = brep.as_compound();
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
|
||||
if (it->hasStyle() && it->Style().Diffuse()) {
|
||||
const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse();
|
||||
surface_styles_.push_back(clr.R());
|
||||
surface_styles_.push_back(clr.G());
|
||||
surface_styles_.push_back(clr.B());
|
||||
} else {
|
||||
surface_styles_.push_back(-1.);
|
||||
surface_styles_.push_back(-1.);
|
||||
surface_styles_.push_back(-1.);
|
||||
}
|
||||
if (it->hasStyle() && it->Style().Transparency()) {
|
||||
surface_styles_.push_back(1. - *it->Style().Transparency());
|
||||
} else {
|
||||
surface_styles_.push_back(1.);
|
||||
}
|
||||
}
|
||||
std::stringstream sstream;
|
||||
BRepTools::Write(compound,sstream);
|
||||
brep_data_ = sstream.str();
|
||||
}
|
||||
|
||||
// todo copied from kernel
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
|
||||
TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t) {
|
||||
if (t.Form() == gp_Identity) {
|
||||
return s;
|
||||
} else {
|
||||
/// @todo set to 1. and exactly 1. or use epsilon?
|
||||
if (t.ScaleFactor() != 1.) {
|
||||
return BRepBuilderAPI_Transform(s, t, true);
|
||||
} else {
|
||||
return s.Moved(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) {
|
||||
if (t.Form() == gp_Other) {
|
||||
return BRepBuilderAPI_GTransform(s, t, true);
|
||||
} else {
|
||||
return apply_transformation(s, t.Trsf());
|
||||
}
|
||||
}
|
||||
|
||||
TopoDS_Compound IfcGeom::Representation::BRep::as_compound(bool force_meters) const {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
gp_GTrsf trsf = it->Placement();
|
||||
if (settings().convert_back_units()) {
|
||||
|
||||
if (!force_meters && settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
|
||||
trsf.PreMultiply(scale);
|
||||
}
|
||||
bool trsf_valid = false;
|
||||
gp_Trsf _trsf;
|
||||
try {
|
||||
_trsf = trsf.Trsf();
|
||||
trsf_valid = true;
|
||||
} catch (...) {}
|
||||
const TopoDS_Shape moved_shape = trsf_valid ? s.Moved(_trsf) :
|
||||
BRepBuilderAPI_GTransform(s,trsf,true).Shape();
|
||||
builder.Add(compound,moved_shape);
|
||||
|
||||
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
|
||||
builder.Add(compound, moved_shape);
|
||||
}
|
||||
std::stringstream sstream;
|
||||
BRepTools::Write(compound,sstream);
|
||||
_brep_data = sstream.str();
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void accumulate(const gp_Ax3& ax, const gp_Dir& normal, double area, double& along_x, double& along_y, double& along_z) {
|
||||
along_x += area * fabs(ax.XDirection().Dot(normal));
|
||||
along_y += area * fabs(ax.YDirection().Dot(normal));
|
||||
along_z += area * fabs(ax.Direction().Dot(normal));
|
||||
}
|
||||
|
||||
void surface_area_along_direction(double tol, const TopoDS_Shape& s, const gp_Ax3& ax, double& along_x, double& along_y, double& along_z) {
|
||||
along_x = along_y = along_z = 0.;
|
||||
|
||||
bool meshed = false;
|
||||
|
||||
TopExp_Explorer exp(s, TopAbs_FACE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
const TopoDS_Face& face = TopoDS::Face(exp.Current());
|
||||
Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
|
||||
Handle(Geom_Plane) plane = Handle(Geom_Plane)::DownCast(surf);
|
||||
|
||||
if (surf->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
|
||||
GProp_GProps prop_area;
|
||||
BRepGProp::SurfaceProperties(face, prop_area);
|
||||
const double area = prop_area.Mass();
|
||||
|
||||
accumulate(ax, plane->Position().Direction(), area, along_x, along_y, along_z);
|
||||
} else {
|
||||
|
||||
if (!meshed) {
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, tol);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
return;
|
||||
}
|
||||
meshed = true;
|
||||
}
|
||||
|
||||
TopLoc_Location loc;
|
||||
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
|
||||
if (!tri.IsNull()) {
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
std::vector<gp_XYZ> coords;
|
||||
coords.reserve(nodes.Length());
|
||||
|
||||
for (int i = 1; i <= nodes.Length(); ++i) {
|
||||
coords.push_back(nodes(i).Transformed(loc).XYZ());
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
|
||||
if (face.Orientation() == TopAbs_REVERSED) {
|
||||
triangles(i).Get(n3, n2, n1);
|
||||
} else {
|
||||
triangles(i).Get(n1, n2, n3);
|
||||
}
|
||||
|
||||
const gp_XYZ& pt1 = coords[n1 - 1];
|
||||
const gp_XYZ& pt2 = coords[n2 - 1];
|
||||
const gp_XYZ& pt3 = coords[n3 - 1];
|
||||
const gp_Vec v1 = pt2 - pt1;
|
||||
const gp_Vec v2 = pt3 - pt2;
|
||||
const gp_Vec v3 = pt1 - pt3;
|
||||
const gp_Vec normal_vector = v1 ^ v2;
|
||||
if (normal_vector.Magnitude() > ALMOST_ZERO) {
|
||||
gp_Dir normal = gp_Dir();
|
||||
|
||||
double edge_lengths[3] = { v1.Magnitude(), v2.Magnitude(), v3.Magnitude() };
|
||||
std::sort(&edge_lengths[0], &edge_lengths[2]);
|
||||
|
||||
const double& a = edge_lengths[0];
|
||||
const double& b = edge_lengths[1];
|
||||
const double& c = edge_lengths[2];
|
||||
|
||||
const double area = 0.25 * sqrt((a + (b + c))*(c - (a - b))*(c + (a - b))*(a + (b - c)));
|
||||
accumulate(ax, normal, area, along_x, along_y, along_z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Representation::BRep::calculate_surface_area(double& area) const {
|
||||
try {
|
||||
area = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
GProp_GProps prop;
|
||||
BRepGProp::SurfaceProperties(it->Shape(), prop);
|
||||
area += prop.Mass();
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (...) {
|
||||
Logger::Error("Error during calculation of surface area");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const {
|
||||
try {
|
||||
volume = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
if (Kernel::is_manifold(it->Shape())) {
|
||||
GProp_GProps prop;
|
||||
BRepGProp::VolumeProperties(it->Shape(), prop);
|
||||
volume += prop.Mass();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (...) {
|
||||
Logger::Error("Error during calculation of volume");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const gp_Ax3 & ax, double & along_x, double & along_y, double & along_z) const {
|
||||
try {
|
||||
along_x = along_y = along_z = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
double x, y, z;
|
||||
surface_area_along_direction(settings().deflection_tolerance(), it->Shape(), ax, x, y, z);
|
||||
|
||||
if (Kernel::is_manifold(it->Shape())) {
|
||||
x /= 2.;
|
||||
y /= 2.;
|
||||
z /= 2.;
|
||||
}
|
||||
|
||||
along_x += x;
|
||||
along_y += y;
|
||||
along_z += z;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (...) {
|
||||
Logger::Error("Error during calculation of projected surface area");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,54 +27,72 @@
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <GCPnts_QuasiUniformDeflection.hxx>
|
||||
#include <Geom_SphericalSurface.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
#include <TopoDS_Compound.hxx>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
namespace Representation {
|
||||
|
||||
class Representation {
|
||||
class IFC_GEOM_API Representation {
|
||||
Representation(const Representation&); //N/A
|
||||
Representation& operator =(const Representation&); //N/A
|
||||
protected:
|
||||
const ElementSettings _settings;
|
||||
const ElementSettings settings_;
|
||||
public:
|
||||
explicit Representation(const ElementSettings& settings)
|
||||
: _settings(settings)
|
||||
: settings_(settings)
|
||||
{}
|
||||
const ElementSettings& settings() const { return _settings; }
|
||||
const ElementSettings& settings() const { return settings_; }
|
||||
virtual ~Representation() {}
|
||||
};
|
||||
|
||||
class BRep : public Representation {
|
||||
class IFC_GEOM_API BRep : public Representation {
|
||||
private:
|
||||
unsigned int id;
|
||||
const IfcGeom::IfcRepresentationShapeItems shapes;
|
||||
std::string id_;
|
||||
const IfcGeom::IfcRepresentationShapeItems shapes_;
|
||||
BRep(const BRep& other);
|
||||
BRep& operator=(const BRep& other);
|
||||
public:
|
||||
BRep(const ElementSettings& settings, unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes)
|
||||
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::IfcRepresentationShapeItems& shapes)
|
||||
: Representation(settings)
|
||||
, id(id)
|
||||
, shapes(shapes)
|
||||
, id_(id)
|
||||
, shapes_(shapes)
|
||||
{}
|
||||
virtual ~BRep() {}
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes.begin(); }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes.end(); }
|
||||
const unsigned int& getId() const { return id; }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes_.begin(); }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes_.end(); }
|
||||
const IfcGeom::IfcRepresentationShapeItems& shapes() const { return shapes_; }
|
||||
const std::string& id() const { return id_; }
|
||||
TopoDS_Compound as_compound(bool force_meters = false) const;
|
||||
|
||||
bool calculate_volume(double&) const;
|
||||
bool calculate_surface_area(double&) const;
|
||||
bool calculate_projected_surface_area(const gp_Ax3& ax, double& along_x, double& along_y, double& along_z) const;
|
||||
};
|
||||
|
||||
class Serialization : public Representation {
|
||||
class IFC_GEOM_API Serialization : public Representation {
|
||||
private:
|
||||
int _id;
|
||||
std::string _brep_data;
|
||||
std::string id_;
|
||||
std::string brep_data_;
|
||||
std::vector<double> surface_styles_;
|
||||
public:
|
||||
int id() const { return _id; }
|
||||
const std::string& brep_data() const { return _brep_data; }
|
||||
const std::string& brep_data() const { return brep_data_; }
|
||||
const std::vector<double>& surface_styles() const { return surface_styles_; }
|
||||
Serialization(const BRep& brep);
|
||||
virtual ~Serialization() {}
|
||||
const std::string& id() const { return id_; }
|
||||
private:
|
||||
Serialization();
|
||||
Serialization(const Serialization&);
|
||||
@@ -91,69 +109,70 @@ namespace IfcGeom {
|
||||
typedef std::map<VertexKey, int> VertexKeyMap;
|
||||
typedef std::pair<int, int> Edge;
|
||||
|
||||
int _id;
|
||||
std::string id_;
|
||||
std::vector<P> _verts;
|
||||
std::vector<int> _faces;
|
||||
std::vector<int> _edges;
|
||||
std::vector<P> _normals;
|
||||
std::vector<P> uvs_;
|
||||
std::vector<int> _material_ids;
|
||||
std::vector<Material> _materials;
|
||||
VertexKeyMap welds;
|
||||
|
||||
public:
|
||||
int id() const { return _id; }
|
||||
const std::string& id() const { return id_; }
|
||||
const std::vector<P>& verts() const { return _verts; }
|
||||
const std::vector<int>& faces() const { return _faces; }
|
||||
const std::vector<int>& edges() const { return _edges; }
|
||||
const std::vector<P>& normals() const { return _normals; }
|
||||
const std::vector<P>& uvs() const { return uvs_; }
|
||||
const std::vector<int>& material_ids() const { return _material_ids; }
|
||||
const std::vector<Material>& materials() const { return _materials; }
|
||||
|
||||
Triangulation(const BRep& shape_model)
|
||||
: Representation(shape_model.settings())
|
||||
, _id(shape_model.getId())
|
||||
, id_(shape_model.id())
|
||||
{
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shape_model.begin(); it != shape_model.end(); ++ it ) {
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
|
||||
|
||||
int surface_style_id = -1;
|
||||
if (it->hasStyle()) {
|
||||
Material adapter(&it->Style());
|
||||
if (iit->hasStyle()) {
|
||||
Material adapter(&iit->Style());
|
||||
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
|
||||
if (jt == _materials.end()) {
|
||||
surface_style_id = _materials.size();
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(adapter);
|
||||
} else {
|
||||
surface_style_id = jt - _materials.begin();
|
||||
surface_style_id = (int)(jt - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
if (settings().apply_default_materials() && surface_style_id == -1) {
|
||||
if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
|
||||
Material material(IfcGeom::get_default_style(settings().element_type()));
|
||||
std::vector<Material>::const_iterator it = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (it == _materials.end()) {
|
||||
surface_style_id = _materials.size();
|
||||
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (mit == _materials.end()) {
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(material);
|
||||
} else {
|
||||
surface_style_id = it - _materials.begin();
|
||||
surface_style_id = (int)(mit - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
const gp_GTrsf& trsf = it->Placement();
|
||||
const TopoDS_Shape& s = iit->Shape();
|
||||
const gp_GTrsf& trsf = iit->Placement();
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance());
|
||||
} catch(...) {
|
||||
|
||||
// TODO: Catch outside
|
||||
// Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape");
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
continue;
|
||||
}
|
||||
TopExp_Explorer exp;
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next() ) {
|
||||
int num_faces = 0;
|
||||
TopExp_Explorer exp;
|
||||
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next(), ++num_faces ) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc);
|
||||
@@ -174,8 +193,9 @@ namespace IfcGeom {
|
||||
BRepGProp_Face prop(face);
|
||||
std::map<int,int> dict;
|
||||
|
||||
// Vertex normals are only calculated if vertices are not welded
|
||||
const bool calculate_normals = !settings().weld_vertices();
|
||||
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
|
||||
const bool calculate_normals = !settings().get(IteratorSettings::WELD_VERTICES) &&
|
||||
!settings().get(IteratorSettings::NO_NORMALS);
|
||||
|
||||
for( int i = 1; i <= nodes.Length(); ++ i ) {
|
||||
coords.push_back(nodes(i).Transformed(loc).XYZ());
|
||||
@@ -188,12 +208,24 @@ namespace IfcGeom {
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
if (normal_direction.Magnitude() > ALMOST_ZERO) {
|
||||
if (normal_direction.Magnitude() > 1.e-9) {
|
||||
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
|
||||
} else {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(face);
|
||||
// Special case the normal at the poles of a spherical surface
|
||||
if (surf->DynamicType() == STANDARD_TYPE(Geom_SphericalSurface)) {
|
||||
if (fabs(fabs(uv.Y()) - M_PI / 2.) < 1.e-9) {
|
||||
const bool is_top = uv.Y() > 0;
|
||||
const bool is_forward = face.Orientation() == TopAbs_FORWARD;
|
||||
const double z = (is_top == is_forward) ? 1. : -1.;
|
||||
normal = gp_Dir(gp_XYZ(0, 0, z) * rotation_matrix);
|
||||
}
|
||||
}
|
||||
// TODO: Do the same for conical surfaces, but they are rare in IFC.
|
||||
}
|
||||
_normals.push_back((float)normal.X());
|
||||
_normals.push_back((float)normal.Y());
|
||||
_normals.push_back((float)normal.Z());
|
||||
_normals.push_back(static_cast<P>(normal.X()));
|
||||
_normals.push_back(static_cast<P>(normal.Y()));
|
||||
_normals.push_back(static_cast<P>(normal.Z()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,26 +256,137 @@ namespace IfcGeom {
|
||||
|
||||
_material_ids.push_back(surface_style_id);
|
||||
|
||||
addEdge(n1,n2,edgecount,edges_temp);
|
||||
addEdge(n2,n3,edgecount,edges_temp);
|
||||
addEdge(n3,n1,edgecount,edges_temp);
|
||||
addEdge(dict[n1], dict[n2], edgecount, edges_temp);
|
||||
addEdge(dict[n2], dict[n3], edgecount, edges_temp);
|
||||
addEdge(dict[n3], dict[n1], edgecount, edges_temp);
|
||||
}
|
||||
for ( std::vector<std::pair<int,int> >::const_iterator it = edges_temp.begin(); it != edges_temp.end(); ++it ) {
|
||||
_edges.push_back(edgecount[*it]==1);
|
||||
for ( std::vector<std::pair<int,int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt ) {
|
||||
if (edgecount[*jt] == 1) {
|
||||
// non manifold edge, face boundary
|
||||
_edges.push_back(jt->first);
|
||||
_edges.push_back(jt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_normals.empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
|
||||
uvs_ = box_project_uvs(_verts, _normals);
|
||||
}
|
||||
|
||||
if (num_faces == 0) {
|
||||
// Edges are only emitted if there are no faces. A mixed representation of faces
|
||||
// and loose edges is discouraged by the standard. An alternative would be to use
|
||||
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
|
||||
// belong to any face.
|
||||
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
|
||||
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
|
||||
GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance());
|
||||
int n = tessellater.NbPoints();
|
||||
int start = (int)_verts.size() / 3;
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
gp_XYZ p = tessellater.Value(i).XYZ();
|
||||
|
||||
/*
|
||||
// In case you want direction arrows on your edges
|
||||
double u = tessellater.Parameter(i);
|
||||
gp_XYZ p2, p3;
|
||||
gp_Pnt tmp;
|
||||
gp_Vec tmp2;
|
||||
crv.D1(u, tmp, tmp2);
|
||||
gp_Dir d1, d2, d3, d4;
|
||||
d1 = tmp2;
|
||||
if (texp.Current().Orientation() == TopAbs_REVERSED) {
|
||||
d1 = -d1;
|
||||
}
|
||||
if (fabs(d1.Z()) < 0.5) {
|
||||
d2 = d1.Crossed(gp::DZ());
|
||||
} else {
|
||||
d2 = d1.Crossed(gp::DY());
|
||||
}
|
||||
d3 = d1.XYZ() + d2.XYZ();
|
||||
d4 = d1.XYZ() - d2.XYZ();
|
||||
p2 = p - d3.XYZ() / 10.;
|
||||
p3 = p - d4.XYZ() / 10.;
|
||||
trsf.Transforms(p2);
|
||||
trsf.Transforms(p3);
|
||||
_material_ids.push_back(surface_style_id);
|
||||
_material_ids.push_back(surface_style_id);
|
||||
_verts.push_back(static_cast<P>(p2.X()));
|
||||
_verts.push_back(static_cast<P>(p2.Y()));
|
||||
_verts.push_back(static_cast<P>(p2.Z()));
|
||||
_verts.push_back(static_cast<P>(p3.X()));
|
||||
_verts.push_back(static_cast<P>(p3.Y()));
|
||||
_verts.push_back(static_cast<P>(p3.Z()));
|
||||
*/
|
||||
|
||||
trsf.Transforms(p);
|
||||
|
||||
_material_ids.push_back(surface_style_id);
|
||||
|
||||
_verts.push_back(static_cast<P>(p.X()));
|
||||
_verts.push_back(static_cast<P>(p.Y()));
|
||||
_verts.push_back(static_cast<P>(p.Z()));
|
||||
|
||||
if (i > 1) {
|
||||
_edges.push_back(start + i - 2);
|
||||
_edges.push_back(start + i - 1);
|
||||
// _edges.push_back(start + 3 * (i - 2) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
|
||||
// _edges.push_back(start + 3 * (i - 1) + 0);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 1);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BRepTools::Clean(s);
|
||||
}
|
||||
}
|
||||
virtual ~Triangulation() {}
|
||||
|
||||
/// Generates UVs for a single mesh using box projection.
|
||||
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
|
||||
static std::vector<P> box_project_uvs(const std::vector<P> &vertices, const std::vector<P> &normals)
|
||||
{
|
||||
std::vector<P> uvs;
|
||||
uvs.resize(vertices.size() / 3 * 2);
|
||||
for (size_t uv_idx = 0, v_idx = 0;
|
||||
uv_idx < uvs.size() && v_idx < vertices.size() && v_idx < normals.size();
|
||||
uv_idx += 2, v_idx += 3) {
|
||||
|
||||
P n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
|
||||
P v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
|
||||
|
||||
if (std::abs(n_x) > std::abs(n_y) && std::abs(n_x) > std::abs(n_z)) {
|
||||
uvs[uv_idx] = v_z;
|
||||
uvs[uv_idx + 1] = v_y;
|
||||
}
|
||||
if (std::abs(n_y) > std::abs(n_x) && std::abs(n_y) > std::abs(n_z)) {
|
||||
uvs[uv_idx] = v_x;
|
||||
uvs[uv_idx + 1] = v_z;
|
||||
}
|
||||
if (std::abs(n_z) > std::abs(n_x) && std::abs(n_z) > std::abs(n_y)) {
|
||||
uvs[uv_idx] = v_x;
|
||||
uvs[uv_idx + 1] = v_y;
|
||||
}
|
||||
}
|
||||
|
||||
return uvs;
|
||||
}
|
||||
|
||||
private:
|
||||
// Welds vertices that belong to different faces
|
||||
int addVertex(int material_index, const gp_XYZ& p) {
|
||||
const P X = static_cast<P>(settings().convert_back_units() ? (p.X() / settings().unit_magnitude()) : p.X());
|
||||
const P Y = static_cast<P>(settings().convert_back_units() ? (p.Y() / settings().unit_magnitude()) : p.Y());
|
||||
const P Z = static_cast<P>(settings().convert_back_units() ? (p.Z() / settings().unit_magnitude()) : p.Z());
|
||||
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
|
||||
const P X = static_cast<P>(convert ? (p.X() / settings().unit_magnitude()) : p.X());
|
||||
const P Y = static_cast<P>(convert ? (p.Y() / settings().unit_magnitude()) : p.Y());
|
||||
const P Z = static_cast<P>(convert ? (p.Z() / settings().unit_magnitude()) : p.Z());
|
||||
int i = (int) _verts.size() / 3;
|
||||
if (settings().weld_vertices()) {
|
||||
if (settings().get(IteratorSettings::WELD_VERTICES)) {
|
||||
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
|
||||
typename VertexKeyMap::const_iterator it = welds.find(key);
|
||||
if ( it != welds.end() ) return it->second;
|
||||
@@ -269,4 +412,4 @@ namespace IfcGeom {
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,660 @@
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
|
||||
#include <BRepTools_WireExplorer.hxx>
|
||||
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array2OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include "IfcGeom.h"
|
||||
|
||||
template <typename T, typename U>
|
||||
int convert_to_ifc(const T& t, U*& u, bool /*advanced*/) {
|
||||
std::vector<double> coords(3);
|
||||
coords[0] = t.X(); coords[1] = t.Y(); coords[2] = t.Z();
|
||||
u = new U(coords);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcCartesianPoint*& p, bool advanced) {
|
||||
gp_Pnt pnt = BRep_Tool::Pnt(v);
|
||||
return convert_to_ifc(pnt, p, advanced);
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcVertex*& vertex, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
convert_to_ifc(v, p, advanced);
|
||||
vertex = new IfcSchema::IfcVertexPoint(p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const gp_Ax2& a, IfcSchema::IfcAxis2Placement3D*& ax, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
IfcSchema::IfcDirection *x, *z;
|
||||
if (!(convert_to_ifc(a.Location(), p, advanced) && convert_to_ifc(a.Direction(), z, advanced) && convert_to_ifc(a.XDirection(), x, advanced))) {
|
||||
ax = 0;
|
||||
return 0;
|
||||
}
|
||||
ax = new IfcSchema::IfcAxis2Placement3D(p, z, x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void opencascade_array_to_vector(T& t, std::vector<U>& u) {
|
||||
u.reserve(t.Length());
|
||||
for (int i = t.Lower(); i <= t.Upper(); ++i) {
|
||||
u.push_back(t.Value(i));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void opencascade_array_to_vector2(T& t, std::vector< std::vector<U> >& u) {
|
||||
u.reserve(t.RowLength());
|
||||
for (int j = t.LowerRow(); j <= t.UpperRow(); ++j) {
|
||||
std::vector<U> v;
|
||||
v.reserve(t.ColLength());
|
||||
for (int i = t.LowerCol(); i <= t.UpperCol(); ++i) {
|
||||
v.push_back(t.Value(j, i));
|
||||
}
|
||||
u.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcKnotType::Value opencascade_knotspec_to_ifc(GeomAbs_BSplKnotDistribution bspline_knot_spec) {
|
||||
IfcSchema::IfcKnotType::Value knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
|
||||
if (bspline_knot_spec == GeomAbs_Uniform) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNIFORM_KNOTS;
|
||||
} else if (bspline_knot_spec == GeomAbs_QuasiUniform) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_QUASI_UNIFORM_KNOTS;
|
||||
} else if (bspline_knot_spec == GeomAbs_PiecewiseBezier) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_PIECEWISE_BEZIER_KNOTS;
|
||||
}
|
||||
return knot_spec;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool advanced) {
|
||||
if (c->DynamicType() == STANDARD_TYPE(Geom_Line)) {
|
||||
IfcSchema::IfcDirection* d;
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
|
||||
Handle_Geom_Line line = Handle_Geom_Line::DownCast(c);
|
||||
|
||||
if (!convert_to_ifc(line->Position().Location(), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
if (!convert_to_ifc(line->Position().Direction(), d, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcSchema::IfcVector* v = new IfcSchema::IfcVector(d, 1.);
|
||||
curve = new IfcSchema::IfcLine(p, v);
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
|
||||
IfcSchema::IfcAxis2Placement3D* ax;
|
||||
|
||||
Handle_Geom_Circle circle = Handle_Geom_Circle::DownCast(c);
|
||||
|
||||
convert_to_ifc(circle->Position(), ax, advanced);
|
||||
curve = new IfcSchema::IfcCircle(ax, circle->Radius());
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) {
|
||||
IfcSchema::IfcAxis2Placement3D* ax;
|
||||
|
||||
Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(c);
|
||||
|
||||
convert_to_ifc(ellipse->Position(), ax, advanced);
|
||||
curve = new IfcSchema::IfcEllipse(ax, ellipse->MajorRadius(), ellipse->MinorRadius());
|
||||
|
||||
return 1;
|
||||
}
|
||||
#ifdef USE_IFC4
|
||||
else if (c->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
|
||||
Handle_Geom_BSplineCurve bspline = Handle_Geom_BSplineCurve::DownCast(c);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
TColgp_Array1OfPnt poles(1, bspline->NbPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbPoles(); ++i) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (!convert_to_ifc(poles.Value(i), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
points->push(p);
|
||||
}
|
||||
IfcSchema::IfcKnotType::Value knot_spec = opencascade_knotspec_to_ifc(bspline->KnotDistribution());
|
||||
|
||||
std::vector<int> mults;
|
||||
std::vector<double> knots;
|
||||
std::vector<double> weights;
|
||||
|
||||
TColStd_Array1OfInteger bspline_mults(1, bspline->NbKnots());
|
||||
TColStd_Array1OfReal bspline_knots(1, bspline->NbKnots());
|
||||
TColStd_Array1OfReal bspline_weights(1, bspline->NbPoles());
|
||||
|
||||
bspline->Multiplicities(bspline_mults);
|
||||
bspline->Knots(bspline_knots);
|
||||
bspline->Weights(bspline_weights);
|
||||
|
||||
opencascade_array_to_vector(bspline_mults, mults);
|
||||
opencascade_array_to_vector(bspline_knots, knots);
|
||||
opencascade_array_to_vector(bspline_weights, weights);
|
||||
|
||||
bool rational = false;
|
||||
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it) {
|
||||
if ((*it) != 1.) {
|
||||
rational = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rational) {
|
||||
curve = new IfcSchema::IfcRationalBSplineCurveWithKnots(
|
||||
bspline->Degree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
|
||||
bspline->IsClosed() != 0,
|
||||
false,
|
||||
mults,
|
||||
knots,
|
||||
knot_spec,
|
||||
weights
|
||||
);
|
||||
} else {
|
||||
curve = new IfcSchema::IfcBSplineCurveWithKnots(
|
||||
bspline->Degree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
|
||||
bspline->IsClosed() != 0,
|
||||
false,
|
||||
mults,
|
||||
knots,
|
||||
knot_spec
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const Handle_Geom_Surface& s, IfcSchema::IfcSurface*& surface, bool advanced) {
|
||||
if (s->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
|
||||
Handle_Geom_Plane plane = Handle_Geom_Plane::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D* place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(plane->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
surface = new IfcSchema::IfcPlane(place);
|
||||
return 1;
|
||||
}
|
||||
#ifdef USE_IFC4
|
||||
else if (s->DynamicType() == STANDARD_TYPE(Geom_CylindricalSurface)) {
|
||||
Handle_Geom_CylindricalSurface cyl = Handle_Geom_CylindricalSurface::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D* place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(cyl->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
surface = new IfcSchema::IfcCylindricalSurface(place, cyl->Radius());
|
||||
return 1;
|
||||
} else if (s->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) {
|
||||
typedef IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> points_t;
|
||||
|
||||
Handle_Geom_BSplineSurface bspline = Handle_Geom_BSplineSurface::DownCast(s);
|
||||
points_t::ptr points(new points_t);
|
||||
|
||||
TColgp_Array2OfPnt poles(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbUPoles(); ++i) {
|
||||
std::vector<IfcSchema::IfcCartesianPoint*> ps;
|
||||
ps.reserve(bspline->NbVPoles());
|
||||
for (int j = 1; j <= bspline->NbVPoles(); ++j) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (!convert_to_ifc(poles.Value(i, j), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
ps.push_back(p);
|
||||
}
|
||||
points->push(ps);
|
||||
}
|
||||
|
||||
IfcSchema::IfcKnotType::Value knot_spec_u = opencascade_knotspec_to_ifc(bspline->UKnotDistribution());
|
||||
IfcSchema::IfcKnotType::Value knot_spec_v = opencascade_knotspec_to_ifc(bspline->VKnotDistribution());
|
||||
|
||||
if (knot_spec_u != knot_spec_v) {
|
||||
knot_spec_u = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
|
||||
}
|
||||
|
||||
std::vector<int> umults;
|
||||
std::vector<int> vmults;
|
||||
std::vector<double> uknots;
|
||||
std::vector<double> vknots;
|
||||
std::vector< std::vector<double> > weights;
|
||||
|
||||
TColStd_Array1OfInteger bspline_umults(1, bspline->NbUKnots());
|
||||
TColStd_Array1OfInteger bspline_vmults(1, bspline->NbVKnots());
|
||||
TColStd_Array1OfReal bspline_uknots(1, bspline->NbUKnots());
|
||||
TColStd_Array1OfReal bspline_vknots(1, bspline->NbVKnots());
|
||||
TColStd_Array2OfReal bspline_weights(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
|
||||
|
||||
bspline->UMultiplicities(bspline_umults);
|
||||
bspline->VMultiplicities(bspline_vmults);
|
||||
bspline->UKnots(bspline_uknots);
|
||||
bspline->VKnots(bspline_vknots);
|
||||
bspline->Weights(bspline_weights);
|
||||
|
||||
opencascade_array_to_vector(bspline_umults, umults);
|
||||
opencascade_array_to_vector(bspline_vmults, vmults);
|
||||
opencascade_array_to_vector(bspline_uknots, uknots);
|
||||
opencascade_array_to_vector(bspline_vknots, vknots);
|
||||
opencascade_array_to_vector2(bspline_weights, weights);
|
||||
|
||||
bool rational = false;
|
||||
for (std::vector< std::vector<double> >::const_iterator it = weights.begin(); it != weights.end(); ++it) {
|
||||
for (std::vector<double>::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
|
||||
if ((*jt) != 1.) {
|
||||
rational = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rational) {
|
||||
surface = new IfcSchema::IfcRationalBSplineSurfaceWithKnots(
|
||||
bspline->UDegree(),
|
||||
bspline->VDegree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
|
||||
bspline->IsUClosed() != 0,
|
||||
bspline->IsVClosed() != 0,
|
||||
false,
|
||||
umults,
|
||||
vmults,
|
||||
uknots,
|
||||
vknots,
|
||||
knot_spec_u,
|
||||
weights
|
||||
);
|
||||
} else {
|
||||
surface = new IfcSchema::IfcBSplineSurfaceWithKnots(
|
||||
bspline->UDegree(),
|
||||
bspline->VDegree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
|
||||
bspline->IsUClosed() != 0,
|
||||
bspline->IsVClosed() != 0,
|
||||
false,
|
||||
umults,
|
||||
vmults,
|
||||
uknots,
|
||||
vknots,
|
||||
knot_spec_u
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcCurve*& c, bool advanced) {
|
||||
double a, b;
|
||||
IfcSchema::IfcCurve* base;
|
||||
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
|
||||
if (!convert_to_ifc(crv, base, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
trim1->push(new IfcSchema::IfcParameterValue(a));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(b));
|
||||
|
||||
c = new IfcSchema::IfcTrimmedCurve(base, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcEdge*& edge, bool advanced) {
|
||||
double a, b;
|
||||
|
||||
TopExp_Explorer exp(e, TopAbs_VERTEX);
|
||||
if (!exp.More()) return 0;
|
||||
TopoDS_Vertex v1 = TopoDS::Vertex(exp.Current());
|
||||
exp.Next();
|
||||
if (!exp.More()) return 0;
|
||||
TopoDS_Vertex v2 = TopoDS::Vertex(exp.Current());
|
||||
|
||||
IfcSchema::IfcVertex *vertex1, *vertex2;
|
||||
if (!(convert_to_ifc(v1, vertex1, advanced) && convert_to_ifc(v2, vertex2, advanced))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
|
||||
|
||||
if (crv.IsNull()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (crv->DynamicType() == STANDARD_TYPE(Geom_Line) && !advanced) {
|
||||
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdge(vertex1, vertex2);
|
||||
edge = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
return 1;
|
||||
} else {
|
||||
IfcSchema::IfcCurve* curve;
|
||||
if (!convert_to_ifc(crv, curve, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
/// @todo probably not correct
|
||||
const bool sense = e.Orientation() == TopAbs_FORWARD;
|
||||
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, curve, true);
|
||||
edge = new IfcSchema::IfcOrientedEdge(edge2, sense);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Wire& wire, IfcSchema::IfcLoop*& loop, bool advanced) {
|
||||
bool polygonal = true;
|
||||
for (TopExp_Explorer exp(wire, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
double a, b;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b);
|
||||
if (crv.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
|
||||
polygonal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!polygonal && !advanced) {
|
||||
return 0;
|
||||
} else if (polygonal && !advanced) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
for (; exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(exp.CurrentVertex(), p, advanced)) {
|
||||
points->push(p);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
loop = new IfcSchema::IfcPolyLoop(points);
|
||||
return 1;
|
||||
} else {
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcEdge* edge;
|
||||
// With advanced set to true convert_to_ifc(TopoDS_Edge&) will always create an IfcOrientedEdge
|
||||
if (!convert_to_ifc(exp.Current(), edge, true)) {
|
||||
double a, b;
|
||||
if (BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b).IsNull()) {
|
||||
continue;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
edges->push(edge->as<IfcSchema::IfcOrientedEdge>());
|
||||
}
|
||||
loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Face& f, IfcSchema::IfcFace*& face, bool advanced) {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(f);
|
||||
TopExp_Explorer exp(f, TopAbs_WIRE);
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
|
||||
int index = 0;
|
||||
for (; exp.More(); exp.Next(), ++index) {
|
||||
IfcSchema::IfcLoop* loop;
|
||||
if (!convert_to_ifc(TopoDS::Wire(exp.Current()), loop, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
IfcSchema::IfcFaceBound* bnd;
|
||||
if (index == 0) {
|
||||
bnd = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
} else {
|
||||
bnd = new IfcSchema::IfcFaceBound(loop, true);
|
||||
}
|
||||
bounds->push(bnd);
|
||||
}
|
||||
|
||||
const bool is_planar = surf->DynamicType() == STANDARD_TYPE(Geom_Plane);
|
||||
|
||||
if (!is_planar && !advanced) {
|
||||
return 0;
|
||||
}
|
||||
if (is_planar && !advanced) {
|
||||
face = new IfcSchema::IfcFace(bounds);
|
||||
return 1;
|
||||
} else {
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcSurface* surface;
|
||||
if (!convert_to_ifc(surf, surface, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
face = new IfcSchema::IfcAdvancedFace(bounds, surface, f.Orientation() == TopAbs_FORWARD);
|
||||
return 1;
|
||||
#else
|
||||
// No IfcAdvancedFace in Ifc2x3
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
int convert_to_ifc(const TopoDS_Shape& s, U*& item, bool advanced) {
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
IfcSchema::IfcFace* f;
|
||||
|
||||
for (TopExp_Explorer exp(s, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(TopoDS::Face(exp.Current()), f, advanced)) {
|
||||
faces->push(f);
|
||||
} else {
|
||||
/// Cleanup:
|
||||
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
|
||||
IfcEntityList::ptr data = IfcParse::traverse(*it)->unique();
|
||||
for (IfcEntityList::it jt = data->begin(); jt != data->end(); ++jt) {
|
||||
delete *jt;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
item = new U(faces);
|
||||
return faces->size();
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& shape, bool advanced) {
|
||||
#ifndef USE_IFC4
|
||||
advanced = false;
|
||||
#endif
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_COMPSOLID); exp.More();) {
|
||||
/// @todo CompSolids are not supported
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation* rep = 0;
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
// First check if there is a solid with one or more shells
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SOLID); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcClosedShell* outer = 0;
|
||||
IfcSchema::IfcClosedShell::list::ptr inner(new IfcSchema::IfcClosedShell::list);
|
||||
for (TopExp_Explorer exp2(exp.Current(), TopAbs_SHELL); exp2.More(); exp2.Next()) {
|
||||
IfcSchema::IfcClosedShell* shell;
|
||||
if (!convert_to_ifc(exp2.Current(), shell, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
/// @todo Are shells always in this order or does Orientation() needs to be checked?
|
||||
if (outer) {
|
||||
inner->push(shell);
|
||||
} else {
|
||||
outer = shell;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
if (advanced) {
|
||||
if (inner->size()) {
|
||||
items->push(new IfcSchema::IfcAdvancedBrepWithVoids(outer, inner));
|
||||
} else {
|
||||
items->push(new IfcSchema::IfcAdvancedBrep(outer));
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
||||
/// @todo this is not necessarily correct as the shell is not necessarily facetted.
|
||||
if (inner->size()) {
|
||||
items->push(new IfcSchema::IfcFacetedBrepWithVoids(outer, inner));
|
||||
} else {
|
||||
items->push(new IfcSchema::IfcFacetedBrep(outer));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (items->size() > 0) {
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
|
||||
} else {
|
||||
|
||||
// If not, see if there is a shell
|
||||
IfcSchema::IfcOpenShell::list::ptr shells(new IfcSchema::IfcOpenShell::list);
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SHELL); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcOpenShell* shell;
|
||||
if (!convert_to_ifc(exp.Current(), shell, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
shells->push(shell);
|
||||
}
|
||||
|
||||
if (shells->size() > 0) {
|
||||
items->push(new IfcSchema::IfcShellBasedSurfaceModel(shells->generalize()));
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
|
||||
} else {
|
||||
|
||||
// If not, see if there is are one of more faces. Note that they will be grouped into a shell.
|
||||
IfcSchema::IfcOpenShell* shell;
|
||||
int face_count = convert_to_ifc(shape, shell, advanced);
|
||||
|
||||
if (face_count > 0) {
|
||||
items->push(shell);
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
|
||||
} else {
|
||||
|
||||
// If not, see if there are any edges. Note that wires are skipped as
|
||||
// they are not commonly top-level geometrical descriptions in IFC.
|
||||
// Also note that edges are written as trimmed curves rather than edges.
|
||||
|
||||
IfcEntityList::ptr edges(new IfcEntityList);
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcCurve* c;
|
||||
if (!convert_to_ifc(TopoDS::Edge(exp.Current()), c, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
edges->push(c);
|
||||
}
|
||||
|
||||
if (edges->size() == 0) {
|
||||
return 0;
|
||||
} else if (edges->size() == 1) {
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("Curve2D"), edges->as<IfcSchema::IfcRepresentationItem>());
|
||||
} else {
|
||||
// A geometric set is created as that probably (?) makes more sense in IFC
|
||||
IfcSchema::IfcGeometricCurveSet* curves = new IfcSchema::IfcGeometricCurveSet(edges);
|
||||
items->push(curves);
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("GeometricCurveSet"), items->as<IfcSchema::IfcRepresentationItem>());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
reps->push(rep);
|
||||
return new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(tesselate_)(const TopoDS_Shape& shape, double deflection) {
|
||||
BRepMesh_IncrementalMesh(shape, deflection);
|
||||
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
const TopoDS_Face& face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (!tri.IsNull()) {
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
std::vector<IfcSchema::IfcCartesianPoint*> vertices;
|
||||
for (int i = 1; i <= nodes.Length(); ++i) {
|
||||
gp_Pnt pnt = nodes(i).Transformed(loc);
|
||||
std::vector<double> xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
|
||||
IfcSchema::IfcCartesianPoint* cpnt = new IfcSchema::IfcCartesianPoint(xyz);
|
||||
vertices.push_back(cpnt);
|
||||
}
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
triangles(i).Get(n1, n2, n3);
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(vertices[n1 - 1]);
|
||||
points->push(vertices[n2 - 1]);
|
||||
points->push(vertices[n3 - 1]);
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, face.Orientation() != TopAbs_REVERSED);
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face2 = new IfcSchema::IfcFace(bounds);
|
||||
faces->push(face2);
|
||||
}
|
||||
}
|
||||
}
|
||||
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
|
||||
shells->push(shell);
|
||||
IfcSchema::IfcFaceBasedSurfaceModel* surface_model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
items->push(surface_model);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
0, std::string("Facetation"), std::string("SurfaceModel"), items);
|
||||
|
||||
reps->push(rep);
|
||||
IfcSchema::IfcProductDefinitionShape* shapedef = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
|
||||
return shapedef;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMSHAPETYPE_H
|
||||
#define IFCGEOMSHAPETYPE_H
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
enum ShapeType {
|
||||
ST_SHAPELIST,
|
||||
ST_SHAPE,
|
||||
ST_FACE,
|
||||
ST_WIRE,
|
||||
ST_CURVE,
|
||||
ST_EDGE,
|
||||
ST_VERTEX,
|
||||
ST_OTHER
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+667
-210
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,280 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMTREE_H
|
||||
#define IFCGEOMTREE_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
|
||||
#include <NCollection_UBTree.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <BRepAlgoAPI_Common.hxx>
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
#include <BRepClass3d_SolidClassifier.hxx>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
namespace impl {
|
||||
template <typename T>
|
||||
class tree {
|
||||
|
||||
public:
|
||||
|
||||
void add(const T& t, const Bnd_Box& b) {
|
||||
tree_.Add(t, b);
|
||||
}
|
||||
|
||||
void add(const T& t, const TopoDS_Shape& s) {
|
||||
Bnd_Box b;
|
||||
BRepBndLib::AddClose(s, b);
|
||||
add(t, b);
|
||||
shapes_[t] = s;
|
||||
}
|
||||
|
||||
std::vector<T> select_box(const T& t, bool completely_within = false, double extend=-1.e-5) const {
|
||||
typename map_t::const_iterator it = shapes_.find(t);
|
||||
if (it == shapes_.end()) {
|
||||
return std::vector<T>();
|
||||
}
|
||||
|
||||
Bnd_Box b;
|
||||
BRepBndLib::AddClose(it->second, b);
|
||||
|
||||
// Gap is assumed to be positive throughout the codebase,
|
||||
// but at least for IsOut() in the selector a negative
|
||||
// Gap should work as well.
|
||||
b.SetGap(b.GetGap() + extend);
|
||||
|
||||
return select_box(b, completely_within);
|
||||
}
|
||||
|
||||
std::vector<T> select_box(const gp_Pnt& p) const {
|
||||
Bnd_Box b;
|
||||
b.Add(p);
|
||||
return select_box(b);
|
||||
}
|
||||
|
||||
std::vector<T> select_box(const Bnd_Box& b, bool completely_within = false) const {
|
||||
selector s(b);
|
||||
tree_.Select(s);
|
||||
if (completely_within) {
|
||||
std::vector<T> ts = s.results();
|
||||
std::vector<T> ts_filtered;
|
||||
ts_filtered.reserve(ts.size());
|
||||
typename std::vector<T>::const_iterator it = ts.begin();
|
||||
for (; it != ts.end(); ++it) {
|
||||
const TopoDS_Shape& shp = shapes_.find(*it)->second;
|
||||
Bnd_Box B;
|
||||
BRepBndLib::AddClose(shp, B);
|
||||
|
||||
// BndBox::CornerMin() /-Max() introduced in OCCT 6.8
|
||||
double x1, y1, z1, x2, y2, z2;
|
||||
b.Get(x1, y1, z1, x2, y2, z2);
|
||||
double gap = B.GetGap();
|
||||
gp_Pnt p1(x1 - gap, y1 - gap, z1 - gap);
|
||||
gp_Pnt p2(x2 + gap, y2 + gap, z2 + gap);
|
||||
|
||||
if (!b.IsOut(p1) && !b.IsOut(p2)) {
|
||||
ts_filtered.push_back(*it);
|
||||
}
|
||||
}
|
||||
return ts_filtered;
|
||||
} else {
|
||||
return s.results();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<T> select(const T& t, bool completely_within = false) const {
|
||||
std::vector<T> ts = select_box(t);
|
||||
if (ts.empty()) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
std::vector<T> ts_filtered;
|
||||
|
||||
const TopoDS_Shape& A = shapes_.find(t)->second;
|
||||
if (IfcGeom::Kernel::count(A, TopAbs_SHELL) == 0) {
|
||||
return ts_filtered;
|
||||
}
|
||||
|
||||
ts_filtered.reserve(ts.size());
|
||||
|
||||
typename std::vector<T>::const_iterator it = ts.begin();
|
||||
for (it = ts.begin(); it != ts.end(); ++it) {
|
||||
const TopoDS_Shape& B = shapes_.find(*it)->second;
|
||||
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (completely_within) {
|
||||
BRepAlgoAPI_Cut cut(B, A);
|
||||
if (cut.IsDone()) {
|
||||
if (IfcGeom::Kernel::count(cut.Shape(), TopAbs_SHELL) == 0) {
|
||||
ts_filtered.push_back(*it);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BRepAlgoAPI_Common common(A, B);
|
||||
if (common.IsDone()) {
|
||||
if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) {
|
||||
ts_filtered.push_back(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ts_filtered;
|
||||
}
|
||||
|
||||
std::vector<T> select(const TopoDS_Shape& s) const {
|
||||
Bnd_Box bb;
|
||||
BRepBndLib::AddClose(s, bb);
|
||||
|
||||
std::vector<T> ts;
|
||||
|
||||
if (IfcGeom::Kernel::count(s, TopAbs_SHELL) == 0) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
ts = select_box(bb);
|
||||
|
||||
if (ts.empty()) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
std::vector<T> ts_filtered;
|
||||
ts_filtered.reserve(ts.size());
|
||||
|
||||
typename std::vector<T>::const_iterator it = ts.begin();
|
||||
for (it = ts.begin(); it != ts.end(); ++it) {
|
||||
const TopoDS_Shape& B = shapes_.find(*it)->second;
|
||||
|
||||
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BRepAlgoAPI_Common common(s, B);
|
||||
if (common.IsDone()) {
|
||||
if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) {
|
||||
ts_filtered.push_back(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ts_filtered;
|
||||
}
|
||||
|
||||
std::vector<T> select(const gp_Pnt& p) const {
|
||||
std::vector<T> ts = select_box(p);
|
||||
if (ts.empty()) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
std::vector<T> ts_filtered;
|
||||
ts_filtered.reserve(ts.size());
|
||||
|
||||
typename std::vector<T>::const_iterator it = ts.begin();
|
||||
for (it = ts.begin(); it != ts.end(); ++it) {
|
||||
const TopoDS_Shape& B = shapes_.find(*it)->second;
|
||||
TopExp_Explorer exp(B, TopAbs_SOLID);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
BRepClass3d_SolidClassifier cls(exp.Current(), p, 1e-5);
|
||||
if (cls.State() != TopAbs_OUT) {
|
||||
ts_filtered.push_back(*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ts_filtered;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
typedef NCollection_UBTree<T, Bnd_Box> tree_t;
|
||||
typedef std::map<T, TopoDS_Shape> map_t;
|
||||
tree_t tree_;
|
||||
map_t shapes_;
|
||||
|
||||
class selector : public tree_t::Selector
|
||||
{
|
||||
public:
|
||||
selector(const Bnd_Box& b)
|
||||
: tree_t::Selector()
|
||||
, bounds_(b)
|
||||
{}
|
||||
|
||||
Standard_Boolean Reject(const Bnd_Box& b) const {
|
||||
return bounds_.IsOut(b);
|
||||
}
|
||||
|
||||
Standard_Boolean Accept(const T& o) {
|
||||
results_.push_back(o);
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
const std::vector<T>& results() const {
|
||||
return results_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> results_;
|
||||
const Bnd_Box& bounds_;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class tree : public impl::tree<IfcUtil::IfcBaseEntity*> {
|
||||
public:
|
||||
|
||||
tree() {};
|
||||
|
||||
tree(IfcParse::IfcFile& f) {
|
||||
add_file(f, IfcGeom::IteratorSettings());
|
||||
}
|
||||
|
||||
tree(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) {
|
||||
add_file(f, settings);
|
||||
}
|
||||
|
||||
void add_file(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) {
|
||||
IfcGeom::IteratorSettings settings_ = settings;
|
||||
settings_.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
settings_.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
|
||||
settings_.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
|
||||
|
||||
IfcGeom::Iterator<double> it(settings_, &f);
|
||||
|
||||
if (it.initialize()) {
|
||||
do {
|
||||
IfcGeom::BRepElement<double>* elem = (IfcGeom::BRepElement<double>*)it.get();
|
||||
add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), elem->geometry().as_compound());
|
||||
} while (it.next());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+593
-101
@@ -43,6 +43,8 @@
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
|
||||
#include <GC_MakeCircle.hxx>
|
||||
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
@@ -65,6 +67,8 @@
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
@@ -81,11 +85,223 @@
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <ShapeFix_Solid.hxx>
|
||||
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
#include <BRepTools_WireExplorer.hxx>
|
||||
#include <ShapeBuild_ReShape.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
||||
|
||||
#include <BRepAdaptor_CompCurve.hxx>
|
||||
#include <BRepAdaptor_HCompCurve.hxx>
|
||||
#include <Approx_Curve3d.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
namespace {
|
||||
// Returns the other vertex of an edge
|
||||
TopoDS_Vertex other(const TopoDS_Edge& e, const TopoDS_Vertex& v) {
|
||||
TopoDS_Vertex a, b;
|
||||
TopExp::Vertices(e, a, b);
|
||||
return v.IsSame(b) ? a : b;
|
||||
}
|
||||
|
||||
TopoDS_Edge first_edge(const TopoDS_Wire& w) {
|
||||
TopoDS_Vertex v1, v2;
|
||||
TopExp::Vertices(w, v1, v2);
|
||||
TopTools_IndexedDataMapOfShapeListOfShape wm;
|
||||
TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, wm);
|
||||
return TopoDS::Edge(wm.FindFromKey(v1).First());
|
||||
}
|
||||
|
||||
// Returns new wire with the edge replaced by a linear edge with the vertex v moved to p
|
||||
TopoDS_Wire adjust(const TopoDS_Wire& w, const TopoDS_Vertex& v, const gp_Pnt& p) {
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, map);
|
||||
|
||||
bool all_linear = true, single_circle = false, first = true;
|
||||
|
||||
const TopTools_ListOfShape& edges = map.FindFromKey(v);
|
||||
TopTools_ListIteratorOfListOfShape it(edges);
|
||||
for (; it.More(); it.Next()) {
|
||||
const TopoDS_Edge& e = TopoDS::Edge(it.Value());
|
||||
double _, __;
|
||||
Handle(Geom_Curve) crv = BRep_Tool::Curve(e, _, __);
|
||||
const bool is_line = crv->DynamicType() == STANDARD_TYPE(Geom_Line);
|
||||
const bool is_circle = crv->DynamicType() == STANDARD_TYPE(Geom_Circle);
|
||||
all_linear = all_linear && is_line;
|
||||
single_circle = first && is_circle;
|
||||
}
|
||||
|
||||
if (all_linear) {
|
||||
BRep_Builder b;
|
||||
TopoDS_Vertex v2;
|
||||
b.MakeVertex(v2, p, BRep_Tool::Tolerance(v));
|
||||
|
||||
ShapeBuild_ReShape reshape;
|
||||
reshape.Replace(v.Oriented(TopAbs_FORWARD), v2);
|
||||
|
||||
return TopoDS::Wire(reshape.Apply(w));
|
||||
} else if (single_circle) {
|
||||
TopoDS_Vertex v1, v2;
|
||||
TopExp::Vertices(w, v1, v2);
|
||||
|
||||
gp_Pnt p1, p2, p3;
|
||||
p1 = v.IsEqual(v1) ? p : BRep_Tool::Pnt(v1);
|
||||
p3 = v.IsEqual(v2) ? p : BRep_Tool::Pnt(v2);
|
||||
|
||||
double a, b;
|
||||
Handle(Geom_Curve) crv = BRep_Tool::Curve(TopoDS::Edge(edges.First()), a, b);
|
||||
crv->D0((a + b) / 2., p2);
|
||||
|
||||
GC_MakeCircle mc(p1, p2, p3);
|
||||
if (!mc.IsDone()) {
|
||||
throw IfcGeom::geometry_exception("Failed to adjust circle");
|
||||
}
|
||||
|
||||
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(mc.Value(), p1, p3).Edge();
|
||||
BRepBuilderAPI_MakeWire builder;
|
||||
builder.Add(edge);
|
||||
return builder.Wire();
|
||||
} else {
|
||||
throw IfcGeom::geometry_exception("Unexpected wire to adjust");
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper around BRepBuilderAPI_MakeWire that makes sure segments are connected either by moving end points or by adding intermediate segments
|
||||
class wire_builder {
|
||||
private:
|
||||
BRepBuilderAPI_MakeWire mw_;
|
||||
double p_;
|
||||
bool override_next_;
|
||||
gp_Pnt next_override_;
|
||||
const IfcUtil::IfcBaseClass* inst_;
|
||||
|
||||
public:
|
||||
wire_builder(double p, const IfcUtil::IfcBaseClass* inst = 0) : p_(p), override_next_(false), inst_(inst) {}
|
||||
|
||||
void operator()(const TopoDS_Shape& a) {
|
||||
const TopoDS_Wire& w = TopoDS::Wire(a);
|
||||
if (override_next_) {
|
||||
override_next_ = false;
|
||||
TopoDS_Edge e = first_edge(w);
|
||||
mw_.Add(adjust(w, TopExp::FirstVertex(e, true), next_override_));
|
||||
} else {
|
||||
mw_.Add(w);
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const TopoDS_Shape& a, const TopoDS_Shape& b, bool last) {
|
||||
TopoDS_Wire w1 = TopoDS::Wire(a);
|
||||
const TopoDS_Wire& w2 = TopoDS::Wire(b);
|
||||
|
||||
if (override_next_) {
|
||||
override_next_ = false;
|
||||
TopoDS_Edge e = first_edge(w1);
|
||||
w1 = adjust(w1, TopExp::FirstVertex(e, true), next_override_);
|
||||
}
|
||||
|
||||
TopoDS_Vertex w11, w12, w21, w22;
|
||||
TopExp::Vertices(w1, w11, w12);
|
||||
TopExp::Vertices(w2, w21, w22);
|
||||
|
||||
gp_Pnt p1 = BRep_Tool::Pnt(w12);
|
||||
gp_Pnt p2 = BRep_Tool::Pnt(w21);
|
||||
|
||||
double dist = p1.Distance(p2);
|
||||
|
||||
// Distance is within tolerance, this is fine
|
||||
if (dist < p_) {
|
||||
mw_.Add(w1);
|
||||
goto check;
|
||||
}
|
||||
|
||||
// Distance is too large for attempting to move end points, add intermediate edge
|
||||
if (dist > 1000. * p_) {
|
||||
mw_.Add(w1);
|
||||
mw_.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
Logger::Warning("Added additional segment to close gap with length " + boost::lexical_cast<std::string>(dist) + " to:", inst_);
|
||||
goto check;
|
||||
}
|
||||
|
||||
{
|
||||
TopTools_IndexedDataMapOfShapeListOfShape wmap1, wmap2;
|
||||
|
||||
// Find edges connected to end- and begin vertex
|
||||
TopExp::MapShapesAndAncestors(w1, TopAbs_VERTEX, TopAbs_EDGE, wmap1);
|
||||
TopExp::MapShapesAndAncestors(w2, TopAbs_VERTEX, TopAbs_EDGE, wmap2);
|
||||
|
||||
const TopTools_ListOfShape& last_edges = wmap1.FindFromKey(w12);
|
||||
const TopTools_ListOfShape& first_edges = wmap2.FindFromKey(w21);
|
||||
|
||||
double _, __;
|
||||
if (last_edges.Extent() == 1 && first_edges.Extent() == 1) {
|
||||
Handle(Geom_Curve) c1 = BRep_Tool::Curve(TopoDS::Edge(last_edges.First()), _, __);
|
||||
Handle(Geom_Curve) c2 = BRep_Tool::Curve(TopoDS::Edge(first_edges.First()), _, __);
|
||||
|
||||
const bool is_line1 = c1->DynamicType() == STANDARD_TYPE(Geom_Line);
|
||||
const bool is_line2 = c2->DynamicType() == STANDARD_TYPE(Geom_Line);
|
||||
|
||||
const bool is_circle1 = c1->DynamicType() == STANDARD_TYPE(Geom_Circle);
|
||||
const bool is_circle2 = c2->DynamicType() == STANDARD_TYPE(Geom_Circle);
|
||||
|
||||
// Preferably adjust the segment that is linear
|
||||
if (is_line1 || (is_circle1 && !is_line2)) {
|
||||
mw_.Add(adjust(w1, w12, p2));
|
||||
Logger::Notice("Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_);
|
||||
} else if ((is_line2 || is_circle2) && !last) {
|
||||
mw_.Add(w1);
|
||||
override_next_ = true;
|
||||
next_override_ = p1;
|
||||
Logger::Notice("Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_);
|
||||
} else {
|
||||
// In all other cases an edge is added
|
||||
mw_.Add(w1);
|
||||
mw_.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
Logger::Warning("Added additional segment to close gap with length " + boost::lexical_cast<std::string>(dist) + " to:", inst_);
|
||||
}
|
||||
} else {
|
||||
Logger::Error("Internal error, inconsistent wire segments", inst_);
|
||||
mw_.Add(w1);
|
||||
}
|
||||
}
|
||||
|
||||
check:
|
||||
if (mw_.Error() == BRepBuilderAPI_NonManifoldWire) {
|
||||
Logger::Error("Non-manifold curve segments:", inst_);
|
||||
} else if (mw_.Error() == BRepBuilderAPI_DisconnectedWire) {
|
||||
Logger::Error("Failed to join curve segments:", inst_);
|
||||
}
|
||||
}
|
||||
|
||||
const TopoDS_Wire& wire() { return mw_.Wire(); }
|
||||
};
|
||||
|
||||
template <typename Fn>
|
||||
void shape_pair_enumerate(TopTools_ListIteratorOfListOfShape& it, Fn& fn, bool closed) {
|
||||
bool is_first = true;
|
||||
TopoDS_Shape first, previous, current;
|
||||
for (; it.More(); it.Next(), is_first = false) {
|
||||
current = it.Value();
|
||||
if (is_first) {
|
||||
first = current;
|
||||
} else {
|
||||
fn(previous, current, false);
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
if (closed) {
|
||||
fn(current, first, true);
|
||||
} else {
|
||||
fn(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
|
||||
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l);
|
||||
|
||||
// Temporarily pretend we do have unit information
|
||||
setValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
@@ -99,13 +315,33 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
TopoDS_Wire wire_radians, wire_degrees;
|
||||
try {
|
||||
succes_radians = IfcGeom::Kernel::convert(l,wire_radians);
|
||||
} catch (...) {}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Notice(e);
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Notice(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Notice("Unknown error using radians");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Notice("Unknown error using radians");
|
||||
}
|
||||
|
||||
// Now try degrees
|
||||
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
|
||||
try {
|
||||
succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees);
|
||||
} catch (...) {}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Notice(e);
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Notice(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Notice("Unknown error using degrees");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Notice("Unknown error using degrees");
|
||||
}
|
||||
|
||||
// Restore to unknown unit state
|
||||
setValue(GV_PLANEANGLE_UNIT,-1.0);
|
||||
@@ -121,7 +357,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
use_radians = true;
|
||||
} else {
|
||||
// No heuristic left to prefer the one over the other,
|
||||
// apparently both variants are equally succesful.
|
||||
// apparently both variants are equally successful.
|
||||
// The curve might be composed of only straight segments.
|
||||
// Let's go with the wire created using radians as that
|
||||
// at least is a SI unit.
|
||||
@@ -139,113 +375,171 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
|
||||
return use_radians || use_degrees;
|
||||
}
|
||||
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
//TopoDS_Vertex last_vertex;
|
||||
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
|
||||
|
||||
TopTools_ListOfShape converted_segments;
|
||||
|
||||
for (IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++it) {
|
||||
|
||||
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
|
||||
TopoDS_Wire wire2;
|
||||
if ( !convert_wire(curve,wire2) ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
|
||||
TopoDS_Wire segment;
|
||||
|
||||
if (!convert_wire(curve, segment)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve);
|
||||
continue;
|
||||
}
|
||||
if ( ! (*it)->SameSense() ) wire2.Reverse();
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(wire2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_WIRE);
|
||||
/*if ( it != segments->begin() ) {
|
||||
TopExp_Explorer exp (wire2,TopAbs_VERTEX);
|
||||
const TopoDS_Vertex& first_vertex = TopoDS::Vertex(exp.Current());
|
||||
gp_Pnt first = BRep_Tool::Pnt(first_vertex);
|
||||
gp_Pnt last = BRep_Tool::Pnt(last_vertex);
|
||||
Standard_Real distance = first.Distance(last);
|
||||
if ( distance > ALMOST_ZERO ) {
|
||||
w.Add( BRepBuilderAPI_MakeEdge( last_vertex, first_vertex ) );
|
||||
}
|
||||
}*/
|
||||
w.Add(wire2);
|
||||
//last_vertex = w.Vertex();
|
||||
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
|
||||
return false;
|
||||
|
||||
if (!(*it)->SameSense()) {
|
||||
segment.Reverse();
|
||||
}
|
||||
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(segment, getValue(GV_PRECISION), TopAbs_WIRE);
|
||||
|
||||
converted_segments.Append(segment);
|
||||
|
||||
}
|
||||
wire = w.Wire();
|
||||
|
||||
if (converted_segments.Extent() == 0) {
|
||||
Logger::Message(Logger::LOG_ERROR, "No segment succesfully converted:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
TopoDS_Vertex wire_first_vertex, wire_last_vertex, edge_first_vertex, edge_last_vertex;
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(converted_segments);
|
||||
|
||||
IfcEntityList::ptr profile = l->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1);
|
||||
const bool force_close = profile && profile->size() > 0;
|
||||
|
||||
wire_builder bld(getValue(GV_PRECISION), l);
|
||||
shape_pair_enumerate(it, bld, force_close);
|
||||
wire = bld.wire();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
Below is code to deduce the formula below in SageMath
|
||||
|
||||
| R, b = var('R b')
|
||||
|
|
||||
| Bxy = R * cos(b), R * sin(b)
|
||||
| Cxy = R * cos(b/2), R * sin(b/2)
|
||||
|
|
||||
| def dot(v, w):
|
||||
| return v[0] * w[0] + v[1] * w[1]
|
||||
|
|
||||
| def norm(v):
|
||||
| l = sqrt(v[0]^2 + v[1]^2)
|
||||
| return v[0] / l, v[1] / l
|
||||
|
|
||||
| (R - R*dot(norm(Cxy), norm(Bxy))).full_simplify()
|
||||
*/
|
||||
|
||||
double deflection_for_approximating_circle(double radius, double param) {
|
||||
return -radius * std::cos(1. / 2. * param) * std::cos(param) - radius * std::sin(1. / 2. * param) * std::sin(param) + radius;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
|
||||
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
|
||||
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
|
||||
bool isConic = basis_curve->declaration().is(IfcSchema::IfcConic::Class());
|
||||
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
|
||||
|
||||
Handle(Geom_Curve) curve;
|
||||
if ( !convert_curve(basis_curve,curve) ) return false;
|
||||
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
|
||||
if (shape_type(basis_curve) == ST_CURVE) {
|
||||
if (!convert_curve(basis_curve, curve)) return false;
|
||||
} else if (shape_type(basis_curve) == ST_WIRE) {
|
||||
Logger::Warning("Approximating BasisCurve due to possible discontinuities", l);
|
||||
TopoDS_Wire w;
|
||||
if (!convert_wire(basis_curve, w)) return false;
|
||||
BRepAdaptor_CompCurve cc(w, true);
|
||||
Handle(Adaptor3d_HCurve) hcc = Handle(Adaptor3d_HCurve)(new BRepAdaptor_HCompCurve(cc));
|
||||
// @todo, arbitrary numbers here, note they cannot be too high as contiguous memory is allocated based on them.
|
||||
Approx_Curve3d approx(hcc, getValue(GV_PRECISION), GeomAbs_C0, 10, 10);
|
||||
curve = approx.Curve();
|
||||
} else {
|
||||
Logger::Error("Unknown BasisCurve", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool trim_cartesian = l->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
|
||||
IfcEntityList::ptr trims1 = l->Trim1();
|
||||
IfcEntityList::ptr trims2 = l->Trim2();
|
||||
bool trimmed1 = false;
|
||||
bool trimmed2 = false;
|
||||
|
||||
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
|
||||
double flts[2];
|
||||
gp_Pnt pnts[2];
|
||||
bool has_flts[2] = {false,false};
|
||||
bool has_pnts[2] = {false,false};
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
|
||||
TopoDS_Edge e;
|
||||
|
||||
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
if ( i->declaration().is(IfcSchema::IfcCartesianPoint::Class()) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
|
||||
has_pnts[sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
} else if ( i->declaration().is(IfcSchema::IfcParameterValue::Class()) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[sense_agreement] = value * parameterFactor;
|
||||
has_flts[sense_agreement] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
if ( i->declaration().is(IfcSchema::IfcCartesianPoint::Class()) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
|
||||
has_pnts[1-sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
} else if ( i->declaration().is(IfcSchema::IfcParameterValue::Class()) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[1-sense_agreement] = value * parameterFactor;
|
||||
has_flts[1-sense_agreement] = true;
|
||||
}
|
||||
}
|
||||
|
||||
trim_cartesian &= has_pnts[0] && has_pnts[1];
|
||||
bool trim_cartesian_failed = !trim_cartesian;
|
||||
if ( trim_cartesian ) {
|
||||
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
|
||||
if ( pnts[0].Distance(pnts[1]) < 2 * getValue(GV_PRECISION) ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l);
|
||||
return false;
|
||||
}
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
|
||||
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
|
||||
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
||||
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
||||
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
|
||||
if ( ! e.IsDone() ) {
|
||||
BRepBuilderAPI_EdgeError err = e.Error();
|
||||
FTol.SetTolerance(v1, getValue(GV_PRECISION), TopAbs_VERTEX);
|
||||
FTol.SetTolerance(v2, getValue(GV_PRECISION), TopAbs_VERTEX);
|
||||
BRepBuilderAPI_MakeEdge me (curve,v1,v2);
|
||||
if (!me.IsDone()) {
|
||||
BRepBuilderAPI_EdgeError err = me.Error();
|
||||
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l);
|
||||
trim_cartesian_failed = true;
|
||||
}
|
||||
} else {
|
||||
w.Add(e.Edge());
|
||||
e = me.Edge();
|
||||
}
|
||||
}
|
||||
|
||||
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
|
||||
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
|
||||
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
|
||||
// the vector is normalised when passed to Geom_Line constructor the magnitude
|
||||
// needs to be factored in with the IfcParameterValue here.
|
||||
if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
|
||||
if ( basis_curve->declaration().is(IfcSchema::IfcLine::Class()) ) {
|
||||
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
|
||||
const double magnitude = line->Dir()->Magnitude();
|
||||
flts[0] *= magnitude; flts[1] *= magnitude;
|
||||
}
|
||||
if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) {
|
||||
if ( basis_curve->declaration().is(IfcSchema::IfcEllipse::Class()) ) {
|
||||
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
|
||||
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
@@ -255,17 +549,50 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
flts[1] -= M_PI / 2.;
|
||||
}
|
||||
}
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(curve));
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) {
|
||||
e = BRepBuilderAPI_MakeEdge(curve).Edge();
|
||||
} else {
|
||||
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
|
||||
w.Add(e.Edge());
|
||||
BRepBuilderAPI_MakeEdge me (curve,flts[0],flts[1]);
|
||||
e = me.Edge();
|
||||
}
|
||||
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
|
||||
e = BRepBuilderAPI_MakeEdge(pnts[0], pnts[1]).Edge();
|
||||
}
|
||||
if ( w.IsDone() ) {
|
||||
|
||||
if (isConic) {
|
||||
// Tiny circle segnments can cause issues later on, for example
|
||||
// when the comp curve is used as the sweeping directrix.
|
||||
double a, b;
|
||||
Handle(Geom_Curve) crv = BRep_Tool::Curve(e, a, b);
|
||||
double radius = -1.;
|
||||
if (crv->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
|
||||
radius = Handle(Geom_Circle)::DownCast(crv)->Radius();
|
||||
} else if (crv->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) {
|
||||
// The formula above is for circles, but probably good enough
|
||||
radius = Handle(Geom_Ellipse)::DownCast(crv)->MajorRadius();
|
||||
}
|
||||
if (radius > 0. && deflection_for_approximating_circle(radius, b - a) < getValue(GV_PRECISION)) {
|
||||
TopoDS_Vertex v0, v1;
|
||||
TopExp::Vertices(e, v0, v1);
|
||||
e = TopoDS::Edge(BRepBuilderAPI_MakeEdge(v0, v1).Edge().Oriented(e.Orientation()));
|
||||
Logger::Warning("Subsituted edge with linear approximation", l);
|
||||
}
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
w.Add(e);
|
||||
|
||||
if (w.IsDone()) {
|
||||
wire = w.Wire();
|
||||
|
||||
// When SenseAgreement == .F. the vertices above have been reversed to
|
||||
// comply with the direction of conical curves. The ordering of the
|
||||
// vertices then still needs to be reversed in order to have begin and
|
||||
// end vertex consistent with IFC.
|
||||
if (sense_agreement != 0) { // .F.
|
||||
wire.Reverse();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -283,14 +610,29 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu
|
||||
polygon.Append(pnt);
|
||||
}
|
||||
|
||||
const double eps = getValue(GV_PRECISION) * 10;
|
||||
const bool closed_by_proximity = polygon.Length() >= 3 && polygon.First().Distance(polygon.Last()) < eps;
|
||||
if (closed_by_proximity) {
|
||||
// tfk: note 1-based
|
||||
polygon.Remove(polygon.Length());
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_redundant_points_from_loop(polygon, false);
|
||||
remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps);
|
||||
|
||||
if (polygon.Length() < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakePolygon w;
|
||||
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||
w.Add(polygon.Value(i));
|
||||
}
|
||||
|
||||
if (closed_by_proximity) {
|
||||
w.Close();
|
||||
}
|
||||
|
||||
result = w.Wire();
|
||||
return true;
|
||||
}
|
||||
@@ -309,21 +651,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu
|
||||
// A loop should consist of at least three vertices
|
||||
int original_count = polygon.Length();
|
||||
if (original_count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_redundant_points_from_loop(polygon, true);
|
||||
const double eps = getValue(GV_PRECISION) * 10;
|
||||
remove_duplicate_points_from_loop(polygon, true, eps);
|
||||
|
||||
int count = polygon.Length();
|
||||
if (original_count - count != 0) {
|
||||
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
|
||||
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, ss.str(), l);
|
||||
}
|
||||
|
||||
if (count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -333,7 +676,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu
|
||||
}
|
||||
w.Close();
|
||||
|
||||
result = w.Wire();
|
||||
result = w.Wire();
|
||||
|
||||
TopTools_ListOfShape results;
|
||||
if (wire_intersections(result, results)) {
|
||||
Logger::Error("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected", l);
|
||||
select_largest(results, result);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -344,8 +694,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, To
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
|
||||
if (!pnt1->declaration().is(IfcSchema::IfcCartesianPoint::Class()) || !pnt2->declaration().is(IfcSchema::IfcCartesianPoint::Class())) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -364,36 +714,61 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& res
|
||||
// assumed that a topological wire can be crafted from it. After which an
|
||||
// attempt is made to reconstruct it from the individual curves and the vertices
|
||||
// of the IfcEdgeCurve.
|
||||
const bool is_bounded = l->EdgeGeometry()->is(IfcSchema::Type::IfcBoundedCurve);
|
||||
const bool is_bounded = l->EdgeGeometry()->declaration().is(IfcSchema::IfcBoundedCurve::Class());
|
||||
|
||||
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
|
||||
BRepBuilderAPI_MakeEdge me(crv, p1, p2);
|
||||
if (!me.IsDone()) {
|
||||
return false;
|
||||
}
|
||||
mw.Add(me.Edge());
|
||||
result = mw;
|
||||
return true;
|
||||
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
|
||||
if (!l->SameSense()) std::swap(pnt1, pnt2);
|
||||
TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
if (!l->SameSense()) {
|
||||
result.Reverse();
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
|
||||
while (exp.More()) {
|
||||
const TopoDS_Edge& ed = TopoDS::Edge(exp.Current());
|
||||
Standard_Real u1, u2;
|
||||
Handle(Geom_Curve) ecrv = BRep_Tool::Curve(ed, u1, u2);
|
||||
exp.Next();
|
||||
const bool last = !exp.More();
|
||||
first = false;
|
||||
|
||||
gp_Pnt a, b;
|
||||
|
||||
if (first && last) {
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, p2));
|
||||
a = p1;
|
||||
b = p2;
|
||||
} else if (first) {
|
||||
gp_Pnt pu;
|
||||
ecrv->D0(u2, pu);
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, pu));
|
||||
a = p1;
|
||||
ecrv->D0(u2, b);
|
||||
} else if (last) {
|
||||
gp_Pnt pu;
|
||||
ecrv->D0(u1, pu);
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, pu, p2));
|
||||
ecrv->D0(u1, a);
|
||||
b = p2;
|
||||
} else {
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, u1, u2));
|
||||
BRepBuilderAPI_MakeEdge me(ecrv, u1, u2);
|
||||
if (!me.IsDone()) {
|
||||
return false;
|
||||
}
|
||||
mw.Add(me.Edge());
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
BRep_Builder builder;
|
||||
TopoDS_Vertex v1, v2;
|
||||
/// @todo project first and emit warnings accordingly
|
||||
builder.MakeVertex(v1, a, getValue(GV_PRECISION));
|
||||
builder.MakeVertex(v2, b, getValue(GV_PRECISION));
|
||||
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, v1, v2));
|
||||
|
||||
first = false;
|
||||
}
|
||||
result = mw;
|
||||
return true;
|
||||
@@ -406,32 +781,149 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& resu
|
||||
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
|
||||
IfcSchema::IfcOrientedEdge* e = *it;
|
||||
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) e->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) e->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
continue;
|
||||
|
||||
IfcSchema::IfcEdge* base = e->EdgeElement();
|
||||
TopoDS_Wire w;
|
||||
if (convert_wire(e->EdgeElement(), w)) {
|
||||
if (!e->Orientation()) w.Reverse();
|
||||
mw.Add(w);
|
||||
if (convert_wire(*it, w)) {
|
||||
mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value()));
|
||||
}
|
||||
}
|
||||
result = mw;
|
||||
if (!mw.IsDone()) {
|
||||
return false;
|
||||
}
|
||||
result = mw.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) {
|
||||
if (!l->EdgeStart()->declaration().is(IfcSchema::IfcVertexPoint::Class()) || !l->EdgeEnd()->declaration().is(IfcSchema::IfcVertexPoint::Class())) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->declaration().is(IfcSchema::IfcCartesianPoint::Class()) || !pnt2->declaration().is(IfcSchema::IfcCartesianPoint::Class())) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
|
||||
result = mw.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) {
|
||||
if (convert_wire(l->EdgeElement(), result)) {
|
||||
if (!l->Orientation()) {
|
||||
result.Reverse();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) {
|
||||
TopoDS_Wire temp;
|
||||
if (convert_wire(l->ParentEdge(), result) && convert((IfcSchema::IfcEdge*) l, temp)) {
|
||||
TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
|
||||
Standard_Real u1, u2;
|
||||
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2);
|
||||
TopoDS_Vertex v1, v2;
|
||||
TopExp::Vertices(temp, v1, v2);
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(crv, v1, v2));
|
||||
result = mw.Wire();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcIndexedPolyCurve* l, TopoDS_Wire& result) {
|
||||
|
||||
IfcSchema::IfcCartesianPointList* point_list = l->Points();
|
||||
std::vector< std::vector<double> > coordinates;
|
||||
if (point_list->as<IfcSchema::IfcCartesianPointList2D>()) {
|
||||
coordinates = point_list->as<IfcSchema::IfcCartesianPointList2D>()->CoordList();
|
||||
} else if (point_list->as<IfcSchema::IfcCartesianPointList3D>()) {
|
||||
coordinates = point_list->as<IfcSchema::IfcCartesianPointList3D>()->CoordList();
|
||||
}
|
||||
|
||||
std::vector<gp_Pnt> points;
|
||||
points.reserve(coordinates.size());
|
||||
for (std::vector< std::vector<double> >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) {
|
||||
const std::vector<double>& coords = *it;
|
||||
points.push_back(gp_Pnt(
|
||||
coords.size() < 1 ? 0. : coords[0] * getValue(GV_LENGTH_UNIT),
|
||||
coords.size() < 2 ? 0. : coords[1] * getValue(GV_LENGTH_UNIT),
|
||||
coords.size() < 3 ? 0. : coords[2] * getValue(GV_LENGTH_UNIT)));
|
||||
}
|
||||
|
||||
int max_index = points.size();
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
|
||||
if(l->hasSegments()) {
|
||||
IfcEntityList::ptr segments = l->Segments();
|
||||
for (IfcEntityList::it it = segments->begin(); it != segments->end(); ++it) {
|
||||
IfcUtil::IfcBaseClass* segment = *it;
|
||||
if (segment->declaration().is(IfcSchema::IfcLineIndex::Class())) {
|
||||
IfcSchema::IfcLineIndex* line = (IfcSchema::IfcLineIndex*) segment;
|
||||
std::vector<int> indices = *line;
|
||||
gp_Pnt previous;
|
||||
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
|
||||
if (*jt < 1 || *jt > max_index) {
|
||||
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(*jt));
|
||||
}
|
||||
const gp_Pnt& current = points[*jt - 1];
|
||||
if (jt != indices.begin()) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(previous, current));
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
} else if (segment->declaration().is(IfcSchema::IfcArcIndex::Class())) {
|
||||
IfcSchema::IfcArcIndex* arc = (IfcSchema::IfcArcIndex*) segment;
|
||||
std::vector<int> indices = *arc;
|
||||
if (indices.size() != 3) {
|
||||
throw IfcParse::IfcException("Invalid IfcArcIndex encountered");
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const int& idx = indices[i];
|
||||
if (idx < 1 || idx > max_index) {
|
||||
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(idx));
|
||||
}
|
||||
}
|
||||
const gp_Pnt& a = points[indices[0] - 1];
|
||||
const gp_Pnt& b = points[indices[1] - 1];
|
||||
const gp_Pnt& c = points[indices[2] - 1];
|
||||
Handle(Geom_Circle) circ = GC_MakeCircle(a, b, c).Value();
|
||||
w.Add(BRepBuilderAPI_MakeEdge(circ, a, c));
|
||||
} else {
|
||||
throw IfcParse::IfcException("Unexpected IfcIndexedPolyCurve segment of type " + segment->declaration().name());
|
||||
}
|
||||
}
|
||||
} else if (points.begin() < points.end()) {
|
||||
std::vector<gp_Pnt>::const_iterator previous = points.begin();
|
||||
for (std::vector<gp_Pnt>::const_iterator current = previous+1; current < points.end(); ++current){
|
||||
w.Add(BRepBuilderAPI_MakeEdge(*previous, *current));
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
|
||||
result = w.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+62
-12
@@ -18,34 +18,84 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "IfcGeom.h"
|
||||
#include "IfcGeomShapeType.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
using namespace IfcSchema;
|
||||
using namespace IfcUtil;
|
||||
|
||||
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
|
||||
if (shape_type(l) != ST_SHAPELIST) {
|
||||
TopoDS_Shape shp;
|
||||
if (convert_shape(l, shp)) {
|
||||
r.push_back(IfcGeom::IfcRepresentationShapeItem(l->data().id(), shp, get_style(l->as<IfcSchema::IfcRepresentationItem>())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "IfcRegisterConvertShapes.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::is_shape_collection(const IfcBaseClass* l) {
|
||||
#include "IfcRegisterIsShapeCollection.h"
|
||||
return false;
|
||||
IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) {
|
||||
#include "IfcRegisterShapeType.h"
|
||||
return ST_OTHER;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
const unsigned int id = l->entity->id();
|
||||
const unsigned int id = l->data().id();
|
||||
bool success = false;
|
||||
bool processed = false;
|
||||
bool ignored = false;
|
||||
|
||||
#ifndef NO_CACHE
|
||||
std::map<int,TopoDS_Shape>::const_iterator it = cache.Shape.find(id);
|
||||
if ( it != cache.Shape.end() ) { r = it->second; return true; }
|
||||
#endif
|
||||
const bool include_curves = getValue(GV_DIMENSIONALITY) != +1;
|
||||
const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1;
|
||||
|
||||
IfcGeom::ShapeType st = shape_type(l);
|
||||
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
|
||||
if (st == ST_SHAPELIST) {
|
||||
processed = true;
|
||||
IfcRepresentationShapeItems items;
|
||||
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
|
||||
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
|
||||
#include "IfcRegisterConvertShape.h"
|
||||
if ( processed ) {
|
||||
} else if (st == ST_FACE && include_solids_and_surfaces) {
|
||||
processed = true;
|
||||
success = convert_face(l, r);
|
||||
} else if (st == ST_WIRE && include_curves) {
|
||||
processed = true;
|
||||
TopoDS_Wire w;
|
||||
success = convert_wire(l, w);
|
||||
if (success) {
|
||||
r = w;
|
||||
}
|
||||
} else if (st == ST_CURVE && include_curves) {
|
||||
processed = true;
|
||||
Handle(Geom_Curve) crv;
|
||||
TopoDS_Wire w;
|
||||
success = convert_curve(l, crv) && convert_curve_to_wire(crv, w);
|
||||
if (success) {
|
||||
r = w;
|
||||
}
|
||||
}
|
||||
|
||||
if ( processed && success ) {
|
||||
const double precision = getValue(GV_PRECISION);
|
||||
apply_tolerance(r, precision);
|
||||
#ifndef NO_CACHE
|
||||
cache.Shape[id] = r;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
#endif
|
||||
} else if (!ignored) {
|
||||
const char* const msg = processed
|
||||
? "Failed to convert:"
|
||||
: "No operation defined for:";
|
||||
Logger::Message(Logger::LOG_ERROR, msg, l);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -56,18 +106,18 @@ bool IfcGeom::Kernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
|
||||
if (IfcGeom::Kernel::convert_curve(l, curve)) {
|
||||
return IfcGeom::Kernel::convert_curve_to_wire(curve, r);
|
||||
}
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
#include "IfcRegisterConvertFace.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
|
||||
#include "IfcRegisterConvertCurve.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
|
||||
return false;
|
||||
}
|
||||
@@ -38,26 +38,36 @@
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
|
||||
SHAPES(IfcShellBasedSurfaceModel);
|
||||
SHAPES(IfcFaceBasedSurfaceModel);
|
||||
SHAPES(IfcShapeRepresentation);
|
||||
SHAPES(IfcRepresentation);
|
||||
SHAPES(IfcMappedItem);
|
||||
SHAPES(IfcFacetedBrep);
|
||||
// IfcFacetedBrep included
|
||||
// IfcAdvancedBrep included
|
||||
// IfcFacetedBrepWithVoids included
|
||||
// IfcAdvancedBrepWithVoids included
|
||||
SHAPES(IfcManifoldSolidBrep);
|
||||
SHAPES(IfcGeometricSet);
|
||||
|
||||
#ifdef USE_IFC4
|
||||
SHAPE(IfcCylindricalSurface);
|
||||
SHAPE(IfcAdvancedBrep);
|
||||
// FIXME: Surfaces should have a shape type of their own
|
||||
SHAPE(IfcBSplineSurfaceWithKnots);
|
||||
SHAPE(IfcTriangulatedFaceSet);
|
||||
SHAPE(IfcExtrudedAreaSolidTapered);
|
||||
#endif
|
||||
SHAPE(IfcPlane);
|
||||
SHAPE(IfcExtrudedAreaSolid);
|
||||
SHAPE(IfcRevolvedAreaSolid);
|
||||
SHAPE(IfcConnectedFaceSet);
|
||||
SHAPE(IfcBooleanResult);
|
||||
SHAPE(IfcPolygonalBoundedHalfSpace);
|
||||
SHAPE(IfcHalfSpaceSolid);
|
||||
// FIXME: Surfaces should have a shape type of their own
|
||||
SHAPE(IfcSurfaceOfLinearExtrusion);
|
||||
SHAPE(IfcSurfaceOfRevolution);
|
||||
SHAPE(IfcBlock);
|
||||
@@ -71,9 +81,6 @@ SHAPE(IfcRectangularTrimmedSurface);
|
||||
SHAPE(IfcSurfaceCurveSweptAreaSolid);
|
||||
SHAPE(IfcSweptDiskSolid);
|
||||
|
||||
#ifdef USE_IFC4
|
||||
FACE(IfcAdvancedFace);
|
||||
#endif
|
||||
FACE(IfcArbitraryProfileDefWithVoids);
|
||||
FACE(IfcArbitraryClosedProfileDef);
|
||||
FACE(IfcRoundedRectangleProfileDef);
|
||||
@@ -93,19 +100,31 @@ FACE(IfcEllipseProfileDef);
|
||||
FACE(IfcCenterLineProfileDef);
|
||||
FACE(IfcCompositeProfileDef);
|
||||
FACE(IfcDerivedProfileDef);
|
||||
// IfcFaceSurface included
|
||||
// IfcAdvancedFace included in case of IFC4
|
||||
FACE(IfcFace);
|
||||
|
||||
WIRE(IfcEdgeCurve);
|
||||
WIRE(IfcSubedge);
|
||||
WIRE(IfcOrientedEdge);
|
||||
WIRE(IfcEdge);
|
||||
WIRE(IfcEdgeLoop);
|
||||
WIRE(IfcPolyline);
|
||||
WIRE(IfcPolyLoop);
|
||||
WIRE(IfcCompositeCurve);
|
||||
WIRE(IfcTrimmedCurve);
|
||||
WIRE(IfcArbitraryOpenProfileDef);
|
||||
#ifdef USE_IFC4
|
||||
WIRE(IfcIndexedPolyCurve)
|
||||
#endif
|
||||
|
||||
CURVE(IfcCircle);
|
||||
CURVE(IfcEllipse);
|
||||
CURVE(IfcLine);
|
||||
#ifdef USE_IFC4
|
||||
// IfcRationalBSplineCurveWithKnots included
|
||||
CURVE(IfcBSplineCurveWithKnots);
|
||||
#endif
|
||||
|
||||
CLASS(IfcCartesianPoint,gp_Pnt);
|
||||
CLASS(IfcDirection,gp_Dir);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CURVE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define FACE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,14 +1,23 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPE(T) \
|
||||
if ( !processed && l->is(T::Class()) ) { \
|
||||
if ( !processed && l->declaration().is(IfcSchema::T::Class()) ) { \
|
||||
processed = true; \
|
||||
try { \
|
||||
if ( convert((T*)l,r) ) { \
|
||||
if ( convert((IfcSchema::T*)l,r) ) { \
|
||||
success = true; \
|
||||
} \
|
||||
} catch(...) { } \
|
||||
if ( !success) { \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
|
||||
return false; \
|
||||
} catch (const Standard_Failure& f) { \
|
||||
if (f.GetMessageString() && strlen(f.GetMessageString())) \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l); \
|
||||
else \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
|
||||
return false; \
|
||||
} \
|
||||
if (!success) { \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) { \
|
||||
if ( l->declaration().is(IfcSchema::T::Class()) ) { \
|
||||
try { \
|
||||
return convert((T*)l,r); \
|
||||
} catch (...) { } \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
return convert((IfcSchema::T*)l,r); \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
|
||||
} catch (const Standard_Failure& f) { \
|
||||
if (f.GetMessageString()) \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l); \
|
||||
else \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define WIRE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) return true;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_SHAPELIST;
|
||||
#define SHAPE(T) \
|
||||
if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_SHAPE;
|
||||
#define WIRE(T) \
|
||||
if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_WIRE;
|
||||
#define FACE(T) \
|
||||
if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_FACE;
|
||||
#define CURVE(T) \
|
||||
if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_CURVE;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -23,29 +23,32 @@
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
class IfcRepresentationShapeItem {
|
||||
class IFC_GEOM_API IfcRepresentationShapeItem {
|
||||
private:
|
||||
int id;
|
||||
gp_GTrsf placement;
|
||||
TopoDS_Shape shape;
|
||||
const SurfaceStyle* style;
|
||||
public:
|
||||
IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape, const SurfaceStyle* style)
|
||||
: placement(placement), shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape)
|
||||
: placement(placement), shape(shape), style(0) {}
|
||||
IfcRepresentationShapeItem(const TopoDS_Shape& shape, const SurfaceStyle* style)
|
||||
: shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(const TopoDS_Shape& shape)
|
||||
: shape(shape), style(0) {}
|
||||
IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape, const SurfaceStyle* style)
|
||||
: id(id), placement(placement), shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape)
|
||||
: id(id), placement(placement), shape(shape), style(0) {}
|
||||
IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape, const SurfaceStyle* style)
|
||||
: id(id), shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape)
|
||||
: id(id), shape(shape), style(0) {}
|
||||
void append(const gp_GTrsf& trsf) { placement.Multiply(trsf); }
|
||||
void prepend(const gp_GTrsf& trsf) { placement.PreMultiply(trsf); }
|
||||
const TopoDS_Shape& Shape() const { return shape; }
|
||||
const gp_GTrsf& Placement() const { return placement; }
|
||||
bool hasStyle() const { return style != 0; }
|
||||
const SurfaceStyle& Style() const { return *style; }
|
||||
void setStyle(const SurfaceStyle* newStyle) { style = newStyle; }
|
||||
int ItemId() const { return id; }
|
||||
};
|
||||
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFC_GEOM_API_H
|
||||
#define IFC_GEOM_API_H
|
||||
|
||||
#ifdef IFC_SHARED_BUILD
|
||||
#ifdef _WIN32
|
||||
#ifdef IFC_GEOM_EXPORTS
|
||||
#define IFC_GEOM_API __declspec(dllexport)
|
||||
#else
|
||||
#define IFC_GEOM_API __declspec(dllimport)
|
||||
#endif
|
||||
#else // simply assume *nix + GCC-like compiler
|
||||
#define IFC_GEOM_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
#else
|
||||
#define IFC_GEOM_API
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,235 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/** @file IfcGeomFilter.h
|
||||
@brief A set of predefined product filters for IfcGeom::Iterator */
|
||||
|
||||
#ifndef IFCGEOMFILTER_H
|
||||
#define IFCGEOMFILTER_H
|
||||
|
||||
#include "Kernel.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace IfcGeom {
|
||||
/// The filter function (free or member function) or function object (use boost::ref() to reference to it)
|
||||
/// should return true if the geometry for the product is wanted to be included in the output.
|
||||
/// http://www.boost.org/doc/libs/1_62_0/doc/html/function/tutorial.html
|
||||
typedef boost::function<bool(IfcUtil::IfcBaseEntity*)> filter_t;
|
||||
|
||||
struct filter
|
||||
{
|
||||
filter() : include(false), traverse(false), traverse_openings(false) {}
|
||||
filter(bool incl, bool trav, bool trav_openings = false) : include(incl), traverse(trav), traverse_openings(trav_openings) {}
|
||||
/// Should the product be included (true) or excluded (false).
|
||||
bool include;
|
||||
/// If traversal requested, traverse to the parents to see if they satisfy the criteria. E.g. we might be looking for
|
||||
/// children of a storey named "Level 20", or children of entities that have no representation, e.g. IfcCurtainWall.
|
||||
bool traverse;
|
||||
/// Include opening relationships as part of traversal.
|
||||
bool traverse_openings;
|
||||
/// Optional description for the filtering criteria of this filter.
|
||||
std::string description;
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) const {
|
||||
bool is_match = pred(prod);
|
||||
if (!is_match && traverse) {
|
||||
is_match = traverse_match(prod, pred);
|
||||
}
|
||||
return is_match == include;
|
||||
}
|
||||
|
||||
bool traverse_match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) const
|
||||
{
|
||||
IfcUtil::IfcBaseEntity* parent, *current = prod;
|
||||
while ((parent = IfcGeom::Kernel::get_decomposing_entity(current, traverse_openings)) != nullptr) {
|
||||
if (pred(parent)) {
|
||||
return true;
|
||||
}
|
||||
current = parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct wildcard_filter : public filter {
|
||||
wildcard_filter() : filter(false, false) {}
|
||||
wildcard_filter(bool include, bool traverse, const std::set<std::string>& patterns)
|
||||
: filter(include, traverse) {
|
||||
populate(patterns);
|
||||
}
|
||||
|
||||
std::set<boost::regex> values;
|
||||
|
||||
void populate(const std::set<std::string>& patterns) {
|
||||
values.clear();
|
||||
for(auto& pattern: patterns) {
|
||||
values.insert(wildcard_string_to_regex(pattern));
|
||||
}
|
||||
}
|
||||
|
||||
bool match(const std::string &str) const { return match_values(values, str); }
|
||||
|
||||
static bool match_values(const std::set<boost::regex>& values, const std::string &str) {
|
||||
for(auto& r: values) {
|
||||
if (boost::regex_match(str, r)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boost::regex wildcard_string_to_regex(std::string str) {
|
||||
// Escape all non-"*?" regex special chars
|
||||
static const std::string special_chars = "\\^.$|()[]+/";
|
||||
for(auto c: special_chars) {
|
||||
std::string char_str(1, c);
|
||||
boost::replace_all(str, char_str, "\\" + char_str);
|
||||
}
|
||||
// Convert "*?" to their regex equivalents
|
||||
boost::replace_all(str, "?", ".");
|
||||
boost::replace_all(str, "*", ".*");
|
||||
return boost::regex(str);
|
||||
}
|
||||
};
|
||||
|
||||
/// @note supports only string arguments for now
|
||||
struct attribute_filter : public wildcard_filter {
|
||||
std::string attribute_name;
|
||||
|
||||
attribute_filter() {}
|
||||
attribute_filter(const std::string& attribute_name)
|
||||
: attribute_name(attribute_name) {}
|
||||
|
||||
std::string value(IfcUtil::IfcBaseEntity* prod) const {
|
||||
try {
|
||||
return (std::string) *prod->get(attribute_name);
|
||||
} catch (...) {
|
||||
// Either
|
||||
// (a) not an attribute name for this entity instance
|
||||
// (b) not a string attribute
|
||||
// (c) null for this entity instance
|
||||
// @todo: validate the filters with a reference to the schema
|
||||
// probably in IfcGeomIteratorImplementation
|
||||
return "<invalid>";
|
||||
}
|
||||
}
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod) const {
|
||||
return wildcard_filter::match(value(prod));
|
||||
}
|
||||
|
||||
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
|
||||
return filter::match(prod, std::bind(&attribute_filter::match, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void update_description() {
|
||||
std::stringstream ss;
|
||||
|
||||
ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude");
|
||||
std::vector<std::string> patterns;
|
||||
for (auto& r : values) {
|
||||
patterns.push_back("\"" + r.str() + "\"");
|
||||
}
|
||||
|
||||
ss << " " << attribute_name;
|
||||
ss << " values " << boost::algorithm::join(patterns, " ");
|
||||
|
||||
description = ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct layer_filter : public wildcard_filter {
|
||||
typedef std::map<std::string, IfcUtil::IfcBaseEntity*> layer_map_t;
|
||||
|
||||
layer_filter() {}
|
||||
layer_filter(bool include, bool traverse, const std::set<std::string>& patterns)
|
||||
: wildcard_filter(include, traverse, patterns) {}
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod) const {
|
||||
layer_map_t layers = IfcGeom::Kernel::get_layers(prod);
|
||||
return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end();
|
||||
}
|
||||
|
||||
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
|
||||
return filter::match(prod, std::bind(&layer_filter::match, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
struct wildcards_match {
|
||||
wildcards_match(const std::set<boost::regex>& patterns) : patterns(patterns) {}
|
||||
bool operator()(const layer_map_t::value_type& layer_map_value) const {
|
||||
return wildcard_filter::match_values(patterns, layer_map_value.first);
|
||||
}
|
||||
|
||||
std::set<boost::regex> patterns;
|
||||
};
|
||||
|
||||
void update_description() {
|
||||
std::stringstream ss;
|
||||
ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " layers";
|
||||
std::vector<std::string> str_values;
|
||||
BOOST_FOREACH(const boost::regex& r, values) {
|
||||
str_values.push_back(" \"" + r.str() + "\"");
|
||||
}
|
||||
ss << boost::algorithm::join(str_values, " ");
|
||||
description = ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct entity_filter : public filter {
|
||||
std::set<std::string> entity_names;
|
||||
|
||||
entity_filter() {}
|
||||
entity_filter(bool include, bool traverse, const std::set<std::string>& entity_names)
|
||||
: filter(include, traverse)
|
||||
, entity_names(entity_names) {}
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod) const {
|
||||
// The set is iterated over to able to filter on subtypes.
|
||||
for (auto& name : entity_names) {
|
||||
if (prod->declaration().is(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
|
||||
return filter::match(prod, std::bind(&entity_filter::match, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void update_description() {
|
||||
std::stringstream ss;
|
||||
ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " entities";
|
||||
for (auto& name : entity_names) {
|
||||
ss << " " << name;
|
||||
}
|
||||
description = ss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
|
||||
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
|
||||
* *
|
||||
* IfcGeom::Representation::Triangulation is a class that represents a *
|
||||
* triangulated IfcShapeRepresentation. *
|
||||
* Triangulation.verts is a 1 dimensional vector of float defining the *
|
||||
* cartesian coordinates of the vertices of the triangulated shape in the *
|
||||
* format of [x1,y1,z1,..,xn,yn,zn] *
|
||||
* Triangulation.faces is a 1 dimensional vector of int containing the *
|
||||
* indices of the triangles referencing positions in Triangulation.verts *
|
||||
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
|
||||
* the visibility of the edges that span the faces in Triangulation.faces *
|
||||
* *
|
||||
* IfcGeom::Element represents the actual IfcBuildingElements. *
|
||||
* IfcGeomObject.name is the GUID of the element *
|
||||
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
|
||||
* IfcGeomObject.mesh is a pointer to an IfcMesh *
|
||||
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
|
||||
* orientation and translation of the mesh in relation to the world origin *
|
||||
* *
|
||||
* IfcGeom::Iterator::initialize() *
|
||||
* finds the most suitable representation contexts. Returns true iff *
|
||||
* at least a single representation will process successfully *
|
||||
* *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* returns a pointer to the current IfcGeom::Element *
|
||||
* *
|
||||
* IfcGeom::Iterator::next() *
|
||||
* returns true iff a following entity is available for a successive call to *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* *
|
||||
* IfcGeom::Iterator::progress() *
|
||||
* returns an int in [0..100] that indicates the overall progress *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMITERATOR_H
|
||||
#define IFCGEOMITERATOR_H
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
|
||||
|
||||
// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P = double, typename PP = P>
|
||||
class Iterator {
|
||||
private:
|
||||
Iterator(const Iterator&); // N/I
|
||||
Iterator& operator=(const Iterator&); // N/I
|
||||
|
||||
IfcParse::IfcFile* file_;
|
||||
IfcGeom::IteratorSettings settings_;
|
||||
std::vector<IfcGeom::filter_t> filters_;
|
||||
|
||||
IteratorImplementation<P, PP>* implementation_;
|
||||
|
||||
public:
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file)
|
||||
: file_(file)
|
||||
, settings_(settings)
|
||||
{
|
||||
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), settings, file, filters_);
|
||||
}
|
||||
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters)
|
||||
: file_(file)
|
||||
, settings_(settings)
|
||||
, filters_(filters)
|
||||
{
|
||||
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), settings, file, filters_);
|
||||
}
|
||||
|
||||
bool initialize() {
|
||||
return implementation_->initialize();
|
||||
}
|
||||
|
||||
int progress() const { return implementation_->progress(); }
|
||||
|
||||
void compute_bounds() { implementation_->compute_bounds(); }
|
||||
|
||||
const gp_XYZ& bounds_min() const { return implementation_->bounds_min(); }
|
||||
const gp_XYZ& bounds_max() const { return implementation_->bounds_max(); }
|
||||
|
||||
const std::string& unit_name() const { return implementation_->getUnitName(); }
|
||||
|
||||
double unit_magnitude() const { return implementation_->getUnitMagnitude(); }
|
||||
|
||||
IfcParse::IfcFile* file() const { return implementation_->file(); }
|
||||
|
||||
IfcUtil::IfcBaseClass* next() const { return implementation_->next(); }
|
||||
|
||||
Element<P, PP>* get() { return implementation_->get(); }
|
||||
|
||||
BRepElement<P, PP>* get_native() { return implementation_->get_native(); }
|
||||
|
||||
const Element<P, PP>* get_object(int id) { return implementation_->get_object(id); }
|
||||
|
||||
IfcUtil::IfcBaseClass* create() { return implementation_->create(); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -30,5 +30,6 @@ const double* IfcGeom::Material::diffuse() const { if (hasDiffuse()) return &((*
|
||||
const double* IfcGeom::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; }
|
||||
double IfcGeom::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; }
|
||||
double IfcGeom::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; }
|
||||
const std::string IfcGeom::Material::name() const { return style->Name(); }
|
||||
const std::string &IfcGeom::Material::name() const { return style->Name(); }
|
||||
const std::string &IfcGeom::Material::original_name() const { return style->original_name(); }
|
||||
bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; }
|
||||
@@ -22,11 +22,11 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class Material {
|
||||
class IFC_GEOM_API Material {
|
||||
private:
|
||||
const IfcGeom::SurfaceStyle* style;
|
||||
public:
|
||||
@@ -41,10 +41,11 @@ namespace IfcGeom {
|
||||
const double* specular() const;
|
||||
double transparency() const;
|
||||
double specularity() const;
|
||||
const std::string name() const;
|
||||
const std::string &name() const;
|
||||
const std::string &original_name() const;
|
||||
bool operator==(const Material& other) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
+28
-30
@@ -20,24 +20,20 @@
|
||||
#ifndef IFCGEOMRENDERSTYLES_H
|
||||
#define IFCGEOMRENDERSTYLES_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <tr1/array>
|
||||
#else
|
||||
#include <array>
|
||||
#endif
|
||||
#include "../ifcgeom/ifc_geom_api.h"
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#endif
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace IfcGeom {
|
||||
class SurfaceStyle {
|
||||
class IFC_GEOM_API SurfaceStyle {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
std::tr1::array<double, 3> data;
|
||||
double data[3];
|
||||
public:
|
||||
ColorComponent(double r, double g, double b) {
|
||||
data[0] = r; data[1] = g; data[2] = b;
|
||||
@@ -50,24 +46,27 @@ namespace IfcGeom {
|
||||
double& B() { return data[2]; }
|
||||
};
|
||||
private:
|
||||
boost::optional<std::string> name;
|
||||
std::string name;
|
||||
std::string original_name_;
|
||||
boost::optional<int> id;
|
||||
boost::optional<ColorComponent> diffuse, specular;
|
||||
boost::optional<double> transparency;
|
||||
boost::optional<double> specularity;
|
||||
public:
|
||||
SurfaceStyle() {
|
||||
this->name = "IfcSurfaceStyleShading";
|
||||
}
|
||||
SurfaceStyle() : name("surface-style") {}
|
||||
SurfaceStyle(int id) : id(id) {
|
||||
std::stringstream sstr;
|
||||
sstr << "IfcSurfaceStyleShading_" << id;
|
||||
sstr << "surface-style-" << id;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
SurfaceStyle(const std::string& name) : name(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : id(id) {
|
||||
SurfaceStyle(const std::string& name) : name(name), original_name_(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : original_name_(name), id(id)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << id << "_" << name;
|
||||
std::string sanitized = name;
|
||||
boost::to_lower(sanitized);
|
||||
boost::replace_all(sanitized, " ", "-");
|
||||
sstr << "surface-style-" << id << "-" << sanitized;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
|
||||
@@ -76,16 +75,14 @@ namespace IfcGeom {
|
||||
// pointer addresses of the styles, as they are always referenced
|
||||
// from out of a global map of some sort.
|
||||
bool operator==(const SurfaceStyle& other) {
|
||||
if (name && other.name) {
|
||||
return *name == *other.name;
|
||||
} else if (id && other.id) {
|
||||
return *id == *other.id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return name == other.name;
|
||||
}
|
||||
|
||||
const std::string& Name() const { return *name; }
|
||||
/// ID name, e.g. "surface-style-66675-metal---aluminium"
|
||||
const std::string& Name() const { return name; }
|
||||
|
||||
/// Original name, if available, e.g. "Metal - Aluminium"
|
||||
const std::string& original_name() const { return original_name_; }
|
||||
|
||||
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
|
||||
const boost::optional<ColorComponent>& Specular() const { return specular; }
|
||||
@@ -97,7 +94,8 @@ namespace IfcGeom {
|
||||
boost::optional<double>& Specularity() { return specularity; }
|
||||
};
|
||||
|
||||
const SurfaceStyle* get_default_style(const std::string& ifc_type);
|
||||
IFC_GEOM_API const SurfaceStyle* get_default_style(const std::string& ifc_type);
|
||||
IFC_GEOM_API void set_default_style_file(const std::string& json_file);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "IteratorImplementation.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
template <typename P, typename PP>
|
||||
IteratorFactoryImplementation<P, PP>& iterator_implementations() {
|
||||
static IteratorFactoryImplementation<P, PP> impl;
|
||||
return impl;
|
||||
}
|
||||
|
||||
template IteratorFactoryImplementation<float, float>& iterator_implementations<float, float>();
|
||||
template IteratorFactoryImplementation<float, double>& iterator_implementations<float, double>();
|
||||
template IteratorFactoryImplementation<double, double>& iterator_implementations<double, double>();
|
||||
|
||||
template <typename P, typename PP>
|
||||
extern void init_IteratorImplementation_Ifc2x3(IteratorFactoryImplementation<P, PP>*);
|
||||
|
||||
template <typename P, typename PP>
|
||||
extern void init_IteratorImplementation_Ifc4(IteratorFactoryImplementation<P, PP>*);
|
||||
|
||||
template <typename P, typename PP>
|
||||
IteratorFactoryImplementation<P, PP>::IteratorFactoryImplementation() {
|
||||
init_IteratorImplementation_Ifc2x3(this);
|
||||
init_IteratorImplementation_Ifc4(this);
|
||||
}
|
||||
|
||||
template <typename P, typename PP>
|
||||
void IteratorFactoryImplementation<P, PP>::bind(const std::string& schema_name, typename get_factory_type<P, PP>::type fn) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
this->insert(std::make_pair(schema_name_lower, fn));
|
||||
}
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::IteratorImplementation<P, PP>* IteratorFactoryImplementation<P, PP>::construct(const std::string& schema_name, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
typename std::map<std::string, typename get_factory_type<P, PP>::type>::const_iterator it;
|
||||
it = this->find(schema_name_lower);
|
||||
if (it == this->end()) {
|
||||
throw IfcParse::IfcException("No geometry iterator registered for " + schema_name);
|
||||
}
|
||||
return it->second(settings, file, filters);
|
||||
}
|
||||
|
||||
|
||||
template class IteratorFactoryImplementation<float, float>;
|
||||
template class IteratorFactoryImplementation<float, double>;
|
||||
template class IteratorFactoryImplementation<double, double>;
|
||||
@@ -0,0 +1,81 @@
|
||||
#ifndef ITERATOR_IMPLEMENTATION_H
|
||||
#define ITERATOR_IMPLEMENTATION_H
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
|
||||
#include <gp_XYZ.hxx>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace IfcGeom {
|
||||
template <typename P, typename PP>
|
||||
class IteratorImplementation;
|
||||
|
||||
template <typename P, typename PP>
|
||||
class Element;
|
||||
|
||||
template <typename P, typename PP>
|
||||
class BRepElement;
|
||||
}
|
||||
|
||||
typedef boost::function3<IfcGeom::IteratorImplementation<float, float>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&> iterator_float_float_fn;
|
||||
typedef boost::function3<IfcGeom::IteratorImplementation<float, double>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&> iterator_float_double_fn;
|
||||
typedef boost::function3<IfcGeom::IteratorImplementation<double, double>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&> iterator_double_double_fn;
|
||||
|
||||
template <typename P, typename PP>
|
||||
struct get_factory_type {};
|
||||
|
||||
template <>
|
||||
struct get_factory_type<float, float> {
|
||||
typedef iterator_float_float_fn type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_factory_type<float, double> {
|
||||
typedef iterator_float_double_fn type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_factory_type<double, double> {
|
||||
typedef iterator_double_double_fn type;
|
||||
};
|
||||
|
||||
template <typename P, typename PP>
|
||||
class IteratorFactoryImplementation : public std::map<std::string, typename get_factory_type<P, PP>::type> {
|
||||
public:
|
||||
IteratorFactoryImplementation();
|
||||
void bind(const std::string& schema_name, typename get_factory_type<P, PP>::type fn);
|
||||
IfcGeom::IteratorImplementation<P, PP>* construct(const std::string& schema_name, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&);
|
||||
};
|
||||
|
||||
template <typename P, typename PP>
|
||||
IteratorFactoryImplementation<P, PP>& iterator_implementations();
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P, typename PP>
|
||||
class IteratorImplementation {
|
||||
public:
|
||||
virtual bool initialize() = 0;
|
||||
virtual void compute_bounds() = 0;
|
||||
virtual const gp_XYZ& bounds_min() const = 0;
|
||||
virtual const gp_XYZ& bounds_max() const = 0;
|
||||
virtual int progress() const = 0;
|
||||
virtual const std::string& getUnitName() const = 0;
|
||||
virtual double getUnitMagnitude() const = 0;
|
||||
virtual IfcParse::IfcFile* file() const = 0;
|
||||
virtual IfcUtil::IfcBaseClass* next() = 0;
|
||||
virtual Element<P, PP>* get() = 0;
|
||||
virtual BRepElement<P, PP>* get_native() = 0;
|
||||
virtual const Element<P, PP>* get_object(int id) = 0;
|
||||
virtual IfcUtil::IfcBaseClass* create() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,202 @@
|
||||
#include "Kernel.h"
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <TopTools_IndexedMapOfShape.hxx>
|
||||
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
||||
|
||||
IfcGeom::Kernel::Kernel(IfcParse::IfcFile* file) {
|
||||
if (file != 0) {
|
||||
if (file->schema() == 0) {
|
||||
throw IfcParse::IfcException("No schema associated with file");
|
||||
}
|
||||
|
||||
const std::string& schema_name = file->schema()->name();
|
||||
implementation_ = impl::kernel_implementations().construct(schema_name, file);
|
||||
}
|
||||
}
|
||||
|
||||
int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique) {
|
||||
if (unique) {
|
||||
TopTools_IndexedMapOfShape map;
|
||||
TopExp::MapShapes(s, t, map);
|
||||
return map.Extent();
|
||||
} else {
|
||||
int i = 0;
|
||||
TopExp_Explorer exp(s, t);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int IfcGeom::Kernel::surface_genus(const TopoDS_Shape& s) {
|
||||
int nv = count(s, TopAbs_VERTEX, true);
|
||||
int ne = count(s, TopAbs_EDGE, true);
|
||||
int nf = count(s, TopAbs_FACE, true);
|
||||
|
||||
const int euler = nv - ne + nf;
|
||||
const int genus = (2 - euler) / 2;
|
||||
|
||||
return genus;
|
||||
}
|
||||
|
||||
IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementations() {
|
||||
static KernelFactoryImplementation impl;
|
||||
return impl;
|
||||
}
|
||||
|
||||
extern void init_KernelImplementation_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
extern void init_KernelImplementation_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
|
||||
IfcGeom::impl::KernelFactoryImplementation::KernelFactoryImplementation() {
|
||||
init_KernelImplementation_Ifc2x3(this);
|
||||
init_KernelImplementation_Ifc4(this);
|
||||
}
|
||||
|
||||
void IfcGeom::impl::KernelFactoryImplementation::bind(const std::string& schema_name, IfcGeom::impl::kernel_fn fn) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
this->insert(std::make_pair(schema_name_lower, fn));
|
||||
}
|
||||
|
||||
IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std::string& schema_name, IfcParse::IfcFile* file) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
std::map<std::string, IfcGeom::impl::kernel_fn>::const_iterator it;
|
||||
it = this->find(schema_name_lower);
|
||||
if (it == end()) {
|
||||
throw IfcParse::IfcException("No geometry kernel registered for " + schema_name);
|
||||
}
|
||||
return it->second(file);
|
||||
}
|
||||
|
||||
#define CREATE_GET_DECOMPOSING_ENTITY(IfcSchema) \
|
||||
\
|
||||
IfcSchema::IfcObjectDefinition* get_decomposing_entity_impl(IfcSchema::IfcProduct* product, bool include_openings) {\
|
||||
IfcSchema::IfcObjectDefinition* parent = 0; \
|
||||
\
|
||||
/* In case of an opening element, parent to the RelatingBuildingElement */ \
|
||||
if (include_openings && product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { \
|
||||
IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product; \
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements(); \
|
||||
if (voids->size()) { \
|
||||
IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin(); \
|
||||
parent = ifc_void->RelatingBuildingElement(); \
|
||||
} \
|
||||
} else if (product->declaration().is(IfcSchema::IfcElement::Class())) { \
|
||||
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; \
|
||||
IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); \
|
||||
/* In case of a RelatedBuildingElement parent to the opening element */ \
|
||||
if (fills->size() && include_openings) { \
|
||||
for (IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++it) { \
|
||||
IfcSchema::IfcRelFillsElement* fill = *it; \
|
||||
IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement(); \
|
||||
if (product == ifc_objectdef) continue; \
|
||||
parent = ifc_objectdef; \
|
||||
} \
|
||||
} \
|
||||
/* Else simply parent to the containing structure */ \
|
||||
if (!parent) { \
|
||||
IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure(); \
|
||||
if (parents->size()) { \
|
||||
IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin(); \
|
||||
parent = container->RelatingStructure(); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Parent decompositions to the RelatingObject */ \
|
||||
if (!parent) { \
|
||||
IfcEntityList::ptr parents = product->data().getInverse((&IfcSchema::IfcRelAggregates::Class()), -1); \
|
||||
parents->push(product->data().getInverse((&IfcSchema::IfcRelNests::Class()), -1)); \
|
||||
for (IfcEntityList::it it = parents->begin(); it != parents->end(); ++it) { \
|
||||
IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it; \
|
||||
IfcUtil::IfcBaseEntity* ifc_objectdef; \
|
||||
\
|
||||
ifc_objectdef = get_RelatingObject(decompose); \
|
||||
\
|
||||
if (product == ifc_objectdef) continue; \
|
||||
parent = ifc_objectdef->as<IfcSchema::IfcObjectDefinition>(); \
|
||||
} \
|
||||
} \
|
||||
return parent; \
|
||||
}
|
||||
|
||||
namespace {
|
||||
IfcUtil::IfcBaseEntity* get_RelatingObject(Ifc4::IfcRelDecomposes* decompose) {
|
||||
Ifc4::IfcRelAggregates* aggr = decompose->as<Ifc4::IfcRelAggregates>();
|
||||
if (aggr != nullptr) {
|
||||
return aggr->RelatingObject();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseEntity* get_RelatingObject(Ifc2x3::IfcRelDecomposes* decompose) {
|
||||
return decompose->RelatingObject();
|
||||
}
|
||||
|
||||
CREATE_GET_DECOMPOSING_ENTITY(Ifc2x3);
|
||||
CREATE_GET_DECOMPOSING_ENTITY(Ifc4);
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) {
|
||||
if (inst->as<Ifc2x3::IfcProduct>()) {
|
||||
return get_decomposing_entity_impl(inst->as<Ifc2x3::IfcProduct>(), include_openings);
|
||||
} else if (inst->as<Ifc4::IfcProduct>()) {
|
||||
return get_decomposing_entity_impl(inst->as<Ifc4::IfcProduct>(), include_openings);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name());
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename Schema>
|
||||
static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers_impl(typename Schema::IfcProduct* prod) {
|
||||
std::map<std::string, IfcUtil::IfcBaseEntity*> layers;
|
||||
if (prod->hasRepresentation()) {
|
||||
IfcEntityList::ptr r = IfcParse::traverse(prod->Representation());
|
||||
typename Schema::IfcRepresentation::list::ptr representations = r->as<typename Schema::IfcRepresentation>();
|
||||
for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) {
|
||||
typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments();
|
||||
for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) {
|
||||
layers[(*jt)->Name()] = *jt;
|
||||
}
|
||||
}
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, IfcUtil::IfcBaseEntity*> IfcGeom::Kernel::get_layers(IfcUtil::IfcBaseEntity* inst) {
|
||||
if (inst->as<Ifc2x3::IfcProduct>()) {
|
||||
return get_layers_impl<Ifc2x3>(inst->as<Ifc2x3::IfcProduct>());
|
||||
} else if (inst->as<Ifc4::IfcProduct>()) {
|
||||
return get_layers_impl<Ifc4>(inst->as<Ifc4::IfcProduct>());
|
||||
} else {
|
||||
throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name());
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::is_manifold(const TopoDS_Shape& a) {
|
||||
if (a.ShapeType() == TopAbs_COMPOUND || a.ShapeType() == TopAbs_SOLID) {
|
||||
TopoDS_Iterator it(a);
|
||||
for (; it.More(); it.Next()) {
|
||||
if (!is_manifold(it.Value())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
TopExp::MapShapesAndAncestors(a, TopAbs_EDGE, TopAbs_FACE, map);
|
||||
|
||||
for (int i = 1; i <= map.Extent(); ++i) {
|
||||
if (map.FindFromIndex(i).Extent() != 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#ifndef ITERATOR_KERNEL_H
|
||||
#define ITERATOR_KERNEL_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P, typename PP>
|
||||
class BRepElement;
|
||||
|
||||
class Kernel {
|
||||
private:
|
||||
Kernel* implementation_;
|
||||
|
||||
public:
|
||||
// Tolerances and settings for various geometrical operations:
|
||||
enum GeomValue {
|
||||
// Specifies the deflection of the mesher
|
||||
// Default: 0.001m / 1mm
|
||||
GV_DEFLECTION_TOLERANCE,
|
||||
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
|
||||
// Read-only
|
||||
GV_MINIMAL_FACE_AREA,
|
||||
// Specifies the threshold distance under which cartesian points are deemed equal
|
||||
// Read-only
|
||||
GV_POINT_EQUALITY_TOLERANCE,
|
||||
// Specifies maximum number of faces for a shell to be reoriented.
|
||||
// Default: -1
|
||||
GV_MAX_FACES_TO_ORIENT,
|
||||
// The length unit used the creation of TopoDS_Shapes, primarily affects the
|
||||
// interpretation of IfcCartesianPoints and IfcVector magnitudes
|
||||
// DefaultL 1.0
|
||||
GV_LENGTH_UNIT,
|
||||
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
|
||||
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
|
||||
// Default: -1.0 (= not set, fist try degrees, then radians)
|
||||
GV_PLANEANGLE_UNIT,
|
||||
// The precision used in boolean operations, setting this value too low results
|
||||
// in artefacts and potentially modelling failures
|
||||
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
|
||||
GV_PRECISION,
|
||||
// Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0)
|
||||
GV_DIMENSIONALITY
|
||||
};
|
||||
|
||||
Kernel(IfcParse::IfcFile* file_ = 0);
|
||||
|
||||
virtual ~Kernel() {}
|
||||
|
||||
virtual void setValue(GeomValue var, double value) {
|
||||
implementation_->setValue(var, value);
|
||||
}
|
||||
|
||||
virtual double getValue(GeomValue var) const {
|
||||
return implementation_->getValue(var);
|
||||
}
|
||||
|
||||
virtual BRepElement<double, double>* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
{
|
||||
return implementation_->convert(settings, representation, product);
|
||||
}
|
||||
|
||||
virtual IfcRepresentationShapeItems convert(IfcUtil::IfcBaseClass* item) {
|
||||
return implementation_->convert(item);
|
||||
}
|
||||
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) {
|
||||
return implementation_->convert_placement(item, trsf);
|
||||
}
|
||||
|
||||
static int count(const TopoDS_Shape&, TopAbs_ShapeEnum, bool unique=false);
|
||||
static int surface_genus(const TopoDS_Shape&);
|
||||
|
||||
static bool is_manifold(const TopoDS_Shape& a);
|
||||
static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*, bool include_openings=true);
|
||||
static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*);
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
typedef boost::function1<Kernel*, IfcParse::IfcFile*> kernel_fn;
|
||||
|
||||
class KernelFactoryImplementation : public std::map<std::string, kernel_fn> {
|
||||
public:
|
||||
KernelFactoryImplementation();
|
||||
void bind(const std::string& schema_name, kernel_fn);
|
||||
Kernel* construct(const std::string& schema_name, IfcParse::IfcFile*);
|
||||
};
|
||||
|
||||
KernelFactoryImplementation& kernel_implementations();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "Serialization.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
namespace IfcGeom {
|
||||
extern IfcUtil::IfcBaseClass* tesselate_Ifc2x3(const TopoDS_Shape& shape, double deflection);
|
||||
extern IfcUtil::IfcBaseClass* tesselate_Ifc4(const TopoDS_Shape& shape, double deflection);
|
||||
extern IfcUtil::IfcBaseClass* serialise_Ifc2x3(const TopoDS_Shape& shape, bool advanced);
|
||||
extern IfcUtil::IfcBaseClass* serialise_Ifc4(const TopoDS_Shape& shape, bool advanced);
|
||||
}
|
||||
|
||||
template <typename Fn, typename T>
|
||||
IfcUtil::IfcBaseClass* execute_based_on_schema(Fn fn1, Fn fn2, const std::string& schema_name, const TopoDS_Shape& shape, T t) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
if (schema_name_lower == "ifc2x3") {
|
||||
return fn1(shape, t);
|
||||
} else if (schema_name_lower == "ifc4") {
|
||||
return fn2(shape, t);
|
||||
} else {
|
||||
throw IfcParse::IfcException("No geometry serialization available for " + schema_name);
|
||||
}
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcGeom::tesselate(const std::string& schema_name, const TopoDS_Shape& shape, double deflection) {
|
||||
return execute_based_on_schema(IfcGeom::tesselate_Ifc2x3, IfcGeom::tesselate_Ifc4, schema_name, shape, deflection);
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcGeom::serialise(const std::string& schema_name, const TopoDS_Shape& shape, bool advanced) {
|
||||
return execute_based_on_schema(IfcGeom::serialise_Ifc2x3, IfcGeom::serialise_Ifc4, schema_name, shape, advanced);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "../ifcgeom/ifc_geom_api.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace IfcGeom {
|
||||
IFC_GEOM_API IfcUtil::IfcBaseClass* tesselate(const std::string& schema_name, const TopoDS_Shape& shape, double deflection);
|
||||
IFC_GEOM_API IfcUtil::IfcBaseClass* serialise(const std::string& schema_name, const TopoDS_Shape& shape, bool advanced);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
|
||||
static IfcGeom::SurfaceStyle default_material;
|
||||
static bool default_materials_initialized = false;
|
||||
|
||||
void InitDefaultMaterials() {
|
||||
default_materials.insert(std::make_pair("IfcSite", IfcGeom::SurfaceStyle("IfcSite")));
|
||||
default_materials["IfcSite"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.65));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcSlab", IfcGeom::SurfaceStyle("IfcSlab")));
|
||||
default_materials["IfcSlab"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.4, 0.4, 0.4));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWallStandardCase", IfcGeom::SurfaceStyle("IfcWallStandardCase")));
|
||||
default_materials["IfcWallStandardCase"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9, 0.9, 0.9));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWall", IfcGeom::SurfaceStyle("IfcWall")));
|
||||
default_materials["IfcWall"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9, 0.9, 0.9));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWindow", IfcGeom::SurfaceStyle("IfcWindow")));
|
||||
default_materials["IfcWindow"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.75));
|
||||
default_materials["IfcWindow"].Transparency().reset(0.3);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcDoor", IfcGeom::SurfaceStyle("IfcDoor")));
|
||||
default_materials["IfcDoor"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.55, 0.3, 0.15));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcBeam", IfcGeom::SurfaceStyle("IfcBeam")));
|
||||
default_materials["IfcBeam"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.7, 0.7));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcRailing", IfcGeom::SurfaceStyle("IfcRailing")));
|
||||
default_materials["IfcRailing"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcMember", IfcGeom::SurfaceStyle("IfcMember")));
|
||||
default_materials["IfcMember"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcPlate", IfcGeom::SurfaceStyle("IfcPlate")));
|
||||
default_materials["IfcPlate"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.8, 0.8, 0.8));
|
||||
|
||||
default_material = IfcGeom::SurfaceStyle("DefaultMaterial");
|
||||
default_material.Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.7, 0.7, 0.7));
|
||||
|
||||
default_materials_initialized = true;
|
||||
}
|
||||
|
||||
boost::optional<IfcGeom::SurfaceStyle::ColorComponent> read_colour_component(const boost::optional<pt::ptree&> list) {
|
||||
if (!list) {
|
||||
return boost::none;
|
||||
}
|
||||
double rgb[3];
|
||||
int i = 0;
|
||||
for (pt::ptree::value_type &colour : list.get()) {
|
||||
if (3 <= i) {
|
||||
throw std::runtime_error("rgb array over 3 elements large");
|
||||
}
|
||||
rgb[i] = colour.second.get_value<double>();
|
||||
i++;
|
||||
}
|
||||
if (i != 3) {
|
||||
throw std::runtime_error("rgb array less than 3 elements large (was " + std::to_string(i) + ")");
|
||||
}
|
||||
return IfcGeom::SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
void IfcGeom::set_default_style_file(const std::string& json_file) {
|
||||
if (!default_materials_initialized) InitDefaultMaterials();
|
||||
default_materials.clear();
|
||||
|
||||
// @todo this will probably need to be updated for UTF-8 paths on Windows
|
||||
pt::ptree root;
|
||||
pt::read_json(json_file, root);
|
||||
|
||||
for (pt::ptree::value_type &material_pair : root) {
|
||||
std::string name = material_pair.first;
|
||||
default_materials.insert(std::make_pair(name, IfcGeom::SurfaceStyle(name)));
|
||||
|
||||
pt::ptree material = material_pair.second;
|
||||
boost::optional<pt::ptree&> diffuse = material.get_child_optional("diffuse");
|
||||
default_materials[name].Diffuse() = read_colour_component(diffuse);
|
||||
|
||||
boost::optional<pt::ptree&> specular = material.get_child_optional("specular");
|
||||
default_materials[name].Specular() = read_colour_component(specular);
|
||||
|
||||
if (material.get_child_optional("specular-roughness")) {
|
||||
default_materials[name].Specularity().reset(1.0 / material.get<double>("specular-roughness"));
|
||||
}
|
||||
if (material.get_child_optional("transparency")) {
|
||||
default_materials[name].Transparency() = material.get<double>("transparency");
|
||||
}
|
||||
}
|
||||
|
||||
// Is "*" present? If yes, remove it and make it the default style.
|
||||
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find("*");
|
||||
if (it != default_materials.end()) {
|
||||
IfcGeom::SurfaceStyle star = it->second;
|
||||
default_material.Diffuse() = star.Diffuse();
|
||||
default_material.Specular() = star.Specular();
|
||||
default_material.Specularity() = star.Specularity();
|
||||
default_material.Transparency() = star.Transparency();
|
||||
default_materials.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
|
||||
if (!default_materials_initialized) InitDefaultMaterials();
|
||||
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
|
||||
if (it == default_materials.end()) {
|
||||
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
|
||||
default_materials[s].Diffuse() = default_material.Diffuse();
|
||||
default_materials[s].Specular() = default_material.Specular();
|
||||
default_materials[s].Specularity() = default_material.Specularity();
|
||||
default_materials[s].Transparency() = default_material.Transparency();
|
||||
it = default_materials.find(s);
|
||||
}
|
||||
const IfcGeom::SurfaceStyle& surface_style = it->second;
|
||||
return &surface_style;
|
||||
}
|
||||
@@ -27,23 +27,45 @@
|
||||
#include <iostream>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
// NB: Streams are only re-opened as binary when compiled with MSVC currently.
|
||||
// It is unclear what the correct behaviour would be compiled with e.g MinGW
|
||||
#if defined(_MSC_VER)
|
||||
#define SET_BINARY_STREAMS
|
||||
#endif
|
||||
|
||||
#ifdef SET_BINARY_STREAMS
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
|
||||
using namespace boost;
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
|
||||
#include <memory>
|
||||
|
||||
template <typename T>
|
||||
union data_field {
|
||||
char buffer[sizeof(T)];
|
||||
T value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T sread(std::istream& s) {
|
||||
char buf[sizeof(T)];
|
||||
s.read(buf, sizeof(T));
|
||||
return *((T*)buf);
|
||||
data_field<T> data;
|
||||
s.read(data.buffer, sizeof(T));
|
||||
return data.value;
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -54,10 +76,36 @@ std::string sread(std::istream& s) {
|
||||
buf[len] = 0;
|
||||
while (len++ % 4) s.get();
|
||||
std::string str(buf);
|
||||
delete buf;
|
||||
delete[] buf;
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string format_json(const T& t) {
|
||||
return boost::lexical_cast<std::string>(t);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string format_json(const std::string& s) {
|
||||
// NB: No escaping whatsoever. Only use alphanumeric values.
|
||||
return "\"" + s + "\"";
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string format_json(const double& d) {
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(std::numeric_limits<double>::digits10) << d;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string format_json(const gp_Dir& d) {
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(std::numeric_limits<double>::digits10)
|
||||
<< "[" << d.X() << "," << d.Y() << "," << d.Z() << "]";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::streambuf *stdout_orig, *stdout_redir;
|
||||
|
||||
template <typename T>
|
||||
@@ -69,12 +117,26 @@ void swrite(std::ostream& s, T t) {
|
||||
|
||||
template <>
|
||||
void swrite(std::ostream& s, std::string t) {
|
||||
int32_t len = t.size();
|
||||
int32_t len = (int32_t)t.size();
|
||||
swrite(s, len);
|
||||
s.write(t.c_str(), len);
|
||||
while (len++ % 4) s.put(0);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void swrite_array(std::ostream& s, const std::vector<U>& us) {
|
||||
if (std::is_same<T, U>::value) {
|
||||
swrite(s, std::string((char*)us.data(), us.size() * sizeof(U)));
|
||||
} else {
|
||||
std::vector<T> ts;
|
||||
ts.reserve(us.size());
|
||||
for (auto& u : us) {
|
||||
ts.push_back((T)u);
|
||||
}
|
||||
swrite_array<T, T>(s, ts);
|
||||
}
|
||||
}
|
||||
|
||||
class Command {
|
||||
protected:
|
||||
virtual void read_content(std::istream& s) = 0;
|
||||
@@ -109,6 +171,8 @@ const int32_t NEXT = MORE + 1;
|
||||
const int32_t BYE = NEXT + 1;
|
||||
const int32_t GET_LOG = BYE + 1;
|
||||
const int32_t LOG = GET_LOG + 1;
|
||||
const int32_t DEFLECTION = LOG + 1;
|
||||
const int32_t SETTING = DEFLECTION + 1;
|
||||
|
||||
class Hello : public Command {
|
||||
private:
|
||||
@@ -122,7 +186,7 @@ protected:
|
||||
}
|
||||
public:
|
||||
const std::string& string() { return str; }
|
||||
Hello() : Command(HELLO), str("IfcOpenShell-" IFCOPENSHELL_VERSION) {}
|
||||
Hello() : Command(HELLO), str("IfcOpenShell-" IFCOPENSHELL_VERSION "-0") {}
|
||||
};
|
||||
|
||||
class More : public Command {
|
||||
@@ -156,16 +220,16 @@ public:
|
||||
|
||||
class Get : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
Get() : Command(GET) {};
|
||||
};
|
||||
|
||||
class GetLog : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
GetLog() : Command(GET_LOG) {};
|
||||
};
|
||||
@@ -184,38 +248,107 @@ public:
|
||||
WriteLog(const std::string& str) : Command(LOG), str(str) {};
|
||||
};
|
||||
|
||||
class EntityExtension {
|
||||
protected:
|
||||
bool trailing_, opened_;
|
||||
std::stringstream json_;
|
||||
|
||||
template <typename T>
|
||||
void put_json(const std::string& k, T v) {
|
||||
if (!opened_) {
|
||||
json_ << "{";
|
||||
opened_ = true;
|
||||
}
|
||||
if (trailing_) {
|
||||
json_ << ",";
|
||||
}
|
||||
json_ << format_json(k) << ":" << format_json(v);
|
||||
trailing_ = true;
|
||||
}
|
||||
public:
|
||||
EntityExtension()
|
||||
: trailing_(false)
|
||||
, opened_(false)
|
||||
{}
|
||||
|
||||
void write_contents(std::ostream& s) {
|
||||
if (opened_) {
|
||||
json_ << "}";
|
||||
}
|
||||
|
||||
// We do a 4-byte manual alignment
|
||||
std::string payload = json_.str();
|
||||
s << payload;
|
||||
if (payload.size() % 4) {
|
||||
s << std::string(4 - (payload.size() % 4), ' ');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Entity : public Command {
|
||||
private:
|
||||
const IfcGeom::TriangulationElement<float>* geom;
|
||||
const IfcGeom::TriangulationElement<double, double>* geom;
|
||||
bool append_line_data;
|
||||
EntityExtension* eext_;
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite<int32_t>(s, geom->id());
|
||||
swrite(s, geom->guid());
|
||||
swrite(s, geom->name());
|
||||
swrite(s, geom->type());
|
||||
swrite<int32_t>(s, geom->parent_id());
|
||||
const std::vector<float>& m = geom->transformation().matrix().data();
|
||||
const float matrix_array[16] = {
|
||||
const std::vector<double>& m = geom->transformation().matrix().data();
|
||||
const double matrix_array[16] = {
|
||||
m[0], m[3], m[6], m[ 9],
|
||||
m[1], m[4], m[7], m[10],
|
||||
m[2], m[5], m[8], m[11],
|
||||
0, 0, 0, 1
|
||||
};
|
||||
swrite(s, std::string((char*)matrix_array, 16 * sizeof(float)));
|
||||
swrite<int32_t>(s, geom->geometry().id());
|
||||
swrite(s, std::string((char*)geom->geometry().verts().data(), geom->geometry().verts().size() * sizeof(float)));
|
||||
swrite(s, std::string((char*)geom->geometry().normals().data(), geom->geometry().normals().size() * sizeof(float)));
|
||||
{ std::vector<int32_t> indices;
|
||||
for (std::vector<int>::const_iterator it = geom->geometry().faces().begin(); it != geom->geometry().faces().end(); ++it) {
|
||||
indices.push_back(*it);
|
||||
}
|
||||
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t))); }
|
||||
swrite(s, std::string((char*)matrix_array, 16 * sizeof(double)));
|
||||
|
||||
// The first bit of the string is always the instance name of the representation.
|
||||
const std::string& representation_id = geom->geometry().id();
|
||||
const int integer_representation_id = atoi(representation_id.c_str());
|
||||
swrite<int32_t>(s, (int32_t)integer_representation_id);
|
||||
|
||||
swrite_array<double>(s, geom->geometry().verts());
|
||||
swrite_array<float>(s, geom->geometry().normals());
|
||||
|
||||
{
|
||||
std::vector<int32_t> indices;
|
||||
const std::vector<int>& faces = geom->geometry().faces();
|
||||
indices.reserve(faces.size());
|
||||
for (std::vector<int>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
|
||||
indices.push_back(*it);
|
||||
}
|
||||
swrite_array<int32_t>(s, indices);
|
||||
|
||||
if (append_line_data) {
|
||||
std::vector<int32_t> lines;
|
||||
std::set<int32_t> faces_set (indices.begin(), indices.end());
|
||||
|
||||
const std::vector<int>& edges = geom->geometry().edges();
|
||||
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
|
||||
const int32_t i1 = *(it++);
|
||||
const int32_t i2 = *(it++);
|
||||
|
||||
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lines.push_back(i1);
|
||||
lines.push_back(i2);
|
||||
}
|
||||
|
||||
swrite_array<int32_t>(s, lines);
|
||||
}
|
||||
}
|
||||
{ std::vector<float> diffuse_color_array;
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = geom->geometry().materials().begin(); it != geom->geometry().materials().end(); ++it) {
|
||||
const IfcGeom::Material& m = *it;
|
||||
if (m.hasDiffuse()) {
|
||||
const double* color = m.diffuse();
|
||||
const IfcGeom::Material& mat = *it;
|
||||
if (mat.hasDiffuse()) {
|
||||
const double* color = mat.diffuse();
|
||||
diffuse_color_array.push_back(static_cast<float>(color[0]));
|
||||
diffuse_color_array.push_back(static_cast<float>(color[1]));
|
||||
diffuse_color_array.push_back(static_cast<float>(color[2]));
|
||||
@@ -224,8 +357,8 @@ protected:
|
||||
diffuse_color_array.push_back(0.f);
|
||||
diffuse_color_array.push_back(0.f);
|
||||
}
|
||||
if (m.hasTransparency()) {
|
||||
diffuse_color_array.push_back(static_cast<float>(1. - m.transparency()));
|
||||
if (mat.hasTransparency()) {
|
||||
diffuse_color_array.push_back(static_cast<float>(1. - mat.transparency()));
|
||||
} else {
|
||||
diffuse_color_array.push_back(1.f);
|
||||
}
|
||||
@@ -236,32 +369,156 @@ protected:
|
||||
material_indices.push_back(*it);
|
||||
}
|
||||
swrite(s, std::string((char*) material_indices.data(), material_indices.size() * sizeof(int32_t))); }
|
||||
if (eext_) {
|
||||
eext_->write_contents(s);
|
||||
}
|
||||
}
|
||||
public:
|
||||
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom) {};
|
||||
Entity(const IfcGeom::TriangulationElement<double, double>* geom, EntityExtension* eext = 0) : Command(ENTITY), geom(geom), append_line_data(false), eext_(eext) {};
|
||||
};
|
||||
|
||||
class Next : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
Next() : Command(NEXT) {};
|
||||
};
|
||||
|
||||
class Bye : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
Bye() : Command(BYE) {};
|
||||
};
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
if (sizeof(float) != 4 || sizeof(int32_t) != 4) {
|
||||
return 1;
|
||||
class Deflection : public Command {
|
||||
private:
|
||||
double deflection_;
|
||||
protected:
|
||||
void read_content(std::istream& s) {
|
||||
deflection_ = sread<double>(s);
|
||||
}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite(s, deflection_);
|
||||
}
|
||||
public:
|
||||
Deflection(double d = 0.) : Command(DEFLECTION), deflection_(d) {};
|
||||
double deflection() const { return deflection_; }
|
||||
};
|
||||
|
||||
class Setting : public Command {
|
||||
private:
|
||||
uint32_t id_;
|
||||
uint32_t value_;
|
||||
protected:
|
||||
void read_content(std::istream& s) {
|
||||
id_ = sread<uint32_t>(s);
|
||||
value_ = sread<uint32_t>(s);
|
||||
}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite(s, id_);
|
||||
swrite(s, value_);
|
||||
}
|
||||
public:
|
||||
Setting(uint32_t k = 0, uint32_t v = 0) : Command(SETTING), id_(k), value_(v) {};
|
||||
uint32_t id() const { return id_; }
|
||||
uint32_t value() const { return value_; }
|
||||
};
|
||||
|
||||
static const std::string TOTAL_SURFACE_AREA = "TOTAL_SURFACE_AREA";
|
||||
static const std::string TOTAL_SHAPE_VOLUME = "TOTAL_SHAPE_VOLUME";
|
||||
static const std::string SURFACE_AREA_ALONG_X = "SURFACE_AREA_ALONG_X";
|
||||
static const std::string SURFACE_AREA_ALONG_Y = "SURFACE_AREA_ALONG_Y";
|
||||
static const std::string SURFACE_AREA_ALONG_Z = "SURFACE_AREA_ALONG_Z";
|
||||
static const std::string WALKABLE_SURFACE_AREA = "WALKABLE_SURFACE_AREA";
|
||||
static const std::string LARGEST_FACE_AREA = "LARGEST_FACE_AREA";
|
||||
static const std::string LARGEST_FACE_DIRECTION = "LARGEST_FACE_DIRECTION";
|
||||
static const std::string BOUNDING_BOX_SIZE_ALONG_ = "BOUNDING_BOX_SIZE_ALONG_";
|
||||
static const std::array<std::string, 3> XYZ = { "X", "Y", "Z" };
|
||||
|
||||
class QuantityWriter_v0 : public EntityExtension {
|
||||
private:
|
||||
const IfcGeom::BRepElement<double, double>* elem_;
|
||||
public:
|
||||
QuantityWriter_v0(const IfcGeom::BRepElement<double, double>* elem) :
|
||||
elem_(elem)
|
||||
{
|
||||
put_json(TOTAL_SURFACE_AREA, 0.);
|
||||
put_json(TOTAL_SHAPE_VOLUME, 0.);
|
||||
if (elem_->type() == "IfcSpace") {
|
||||
put_json(WALKABLE_SURFACE_AREA, 0.);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class QuantityWriter_v1 : public EntityExtension {
|
||||
private:
|
||||
const IfcGeom::BRepElement<double, double>* elem_;
|
||||
public:
|
||||
QuantityWriter_v1(const IfcGeom::BRepElement<double, double>* elem) :
|
||||
elem_(elem) {
|
||||
double a, b, c, largest_face_area = 0.;
|
||||
|
||||
if (elem_->geometry().calculate_surface_area(a)) {
|
||||
put_json(TOTAL_SURFACE_AREA, a);
|
||||
}
|
||||
|
||||
if (elem_->geometry().calculate_volume(a)) {
|
||||
put_json(TOTAL_SHAPE_VOLUME, a);
|
||||
}
|
||||
|
||||
if (elem_->calculate_projected_surface_area(a, b, c)) {
|
||||
put_json(SURFACE_AREA_ALONG_X, a);
|
||||
put_json(SURFACE_AREA_ALONG_Y, b);
|
||||
put_json(SURFACE_AREA_ALONG_Z, c);
|
||||
}
|
||||
|
||||
boost::optional<gp_Dir> largest_face_dir;
|
||||
|
||||
{
|
||||
TopoDS_Compound compound = elem_->geometry().as_compound(true);
|
||||
TopExp_Explorer exp(compound, TopAbs_FACE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
GProp_GProps prop;
|
||||
BRepGProp::SurfaceProperties(exp.Current(), prop);
|
||||
const double area = prop.Mass();
|
||||
if (area > largest_face_area) {
|
||||
largest_face_area = area;
|
||||
|
||||
Handle(Geom_Surface) surf = BRep_Tool::Surface(TopoDS::Face(exp.Current()));
|
||||
if (surf->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
|
||||
largest_face_dir = Handle(Geom_Plane)::DownCast(surf)->Axis().Direction();
|
||||
if (exp.Current().Orientation() == TopAbs_REVERSED) {
|
||||
largest_face_dir->Reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bnd_Box box;
|
||||
double xyz[6];
|
||||
|
||||
BRepBndLib::AddClose(compound, box);
|
||||
|
||||
if (!box.IsVoid()) {
|
||||
box.Get(xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5]);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const double bsz = xyz[i + 3] - xyz[i];
|
||||
put_json(BOUNDING_BOX_SIZE_ALONG_ + XYZ[i], bsz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (largest_face_dir) {
|
||||
put_json(LARGEST_FACE_DIRECTION, *largest_face_dir);
|
||||
put_json(LARGEST_FACE_AREA, largest_face_area);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main () {
|
||||
// Redirect stdout to this stream, so that involuntary
|
||||
// writes to stdout do not interfere with our protocol.
|
||||
std::ostringstream oss;
|
||||
@@ -269,6 +526,8 @@ int main (int argc, char** argv) {
|
||||
stdout_orig = std::cout.rdbuf();
|
||||
std::cout.rdbuf(stdout_redir);
|
||||
|
||||
bool emit_quantities = false;
|
||||
|
||||
#ifdef SET_BINARY_STREAMS
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
std::cout.setf(std::ios_base::binary);
|
||||
@@ -276,14 +535,17 @@ int main (int argc, char** argv) {
|
||||
std::cin.setf(std::ios_base::binary);
|
||||
#endif
|
||||
|
||||
double deflection = 1.e-3;
|
||||
bool has_more = false;
|
||||
|
||||
IfcGeom::Iterator<float>* iterator = 0;
|
||||
IfcGeom::Iterator<double, double>* iterator = 0;
|
||||
IfcParse::IfcFile* file = 0;
|
||||
std::vector< std::pair<uint32_t, uint32_t> > setting_pairs;
|
||||
|
||||
Hello().write(std::cout);
|
||||
|
||||
int exit_code = 0;
|
||||
while (1) {
|
||||
for (;;) {
|
||||
const int32_t msg_type = sread<int32_t>(std::cin);
|
||||
switch (msg_type) {
|
||||
case IFC_MODEL: {
|
||||
@@ -293,13 +555,26 @@ int main (int argc, char** argv) {
|
||||
memcpy(data, m.string().c_str(), len);
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.use_world_coords() = false;
|
||||
settings.weld_vertices() = false;
|
||||
settings.convert_back_units() = true;
|
||||
settings.force_ccw_face_orientation() = true;
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
|
||||
// settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, true);
|
||||
|
||||
iterator = new IfcGeom::Iterator<float>(settings, data, len);
|
||||
has_more = iterator->findContext();
|
||||
std::vector< std::pair<uint32_t, uint32_t> >::const_iterator it = setting_pairs.begin();
|
||||
for (; it != setting_pairs.end(); ++it) {
|
||||
settings.set(it->first, it->second != 0);
|
||||
if (it->first == IfcGeom::IteratorSettings::SEW_SHELLS && it->second) {
|
||||
// Quantities (especially volume) can be emitted if there are proper
|
||||
// topologically valid geometries being created.
|
||||
emit_quantities = true;
|
||||
}
|
||||
}
|
||||
|
||||
settings.set_deflection_tolerance(deflection);
|
||||
|
||||
file = new IfcParse::IfcFile(data, (int)len);
|
||||
iterator = new IfcGeom::Iterator<double, double>(settings, file);
|
||||
has_more = iterator->initialize();
|
||||
|
||||
More(has_more).write(std::cout);
|
||||
continue;
|
||||
@@ -310,15 +585,23 @@ int main (int argc, char** argv) {
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
const IfcGeom::TriangulationElement<float>* geom = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator->get());
|
||||
Entity(geom).write(std::cout);
|
||||
const IfcGeom::TriangulationElement<double, double>* geom = static_cast<const IfcGeom::TriangulationElement<double, double>*>(iterator->get());
|
||||
std::unique_ptr<EntityExtension> eext;
|
||||
if (emit_quantities) {
|
||||
eext.reset(new QuantityWriter_v1(iterator->get_native()));
|
||||
} else {
|
||||
eext.reset(new QuantityWriter_v0(iterator->get_native()));
|
||||
}
|
||||
Entity(geom, eext.get()).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case NEXT: {
|
||||
Next n; n.read(std::cin);
|
||||
has_more = iterator->next();
|
||||
has_more = iterator->next() != 0;
|
||||
if (!has_more) {
|
||||
delete file;
|
||||
delete iterator;
|
||||
file = 0;
|
||||
iterator = 0;
|
||||
}
|
||||
More(has_more).write(std::cout);
|
||||
@@ -326,7 +609,7 @@ int main (int argc, char** argv) {
|
||||
}
|
||||
case GET_LOG: {
|
||||
GetLog gl; gl.read(std::cin);
|
||||
WriteLog(iterator->getLog()).write(std::cout);
|
||||
WriteLog(Logger::GetLog()).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case BYE: {
|
||||
@@ -334,7 +617,27 @@ int main (int argc, char** argv) {
|
||||
exit_code = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case DEFLECTION: {
|
||||
Deflection d; d.read(std::cin);
|
||||
if (!iterator) {
|
||||
deflection = d.deflection();
|
||||
continue;
|
||||
} else {
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case SETTING: {
|
||||
Setting s; s.read(std::cin);
|
||||
if (!iterator) {
|
||||
setting_pairs.push_back(std::make_pair(s.id(), s.value()));
|
||||
continue;
|
||||
} else {
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
IfcGeomServer
|
||||
-------------
|
||||
|
||||
A command-line executable intented to be ran as a child process that receives an IFC model from stdin and will send binary geometry information of products found in the IFC file in separate messages on stdout. The advantage over conventional static or dynamic linking is that, in case the IfcOpenShell process would crash (either due to invalid input, heap overflow, bugs, ...), this does not affect the main process. Currently, the only implementation of a consumer for this process is the Java module over at: https://github.com/opensourceBIM/IfcOpenShell-BIMserver-plugin/blob/master/src/org/ifcopenshell/IfcGeomServerClient.java
|
||||
@@ -0,0 +1,47 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
foreach(max_year RANGE 2014 2030)
|
||||
|
||||
set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}")
|
||||
if (NOT "${max_sdk}" STREQUAL "")
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} ${ICU_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIRS} ${max_sdk}/include
|
||||
)
|
||||
|
||||
# All recent versions of 3ds Max (2014 and newer) are 64-bit only so assume lib/x64 directory
|
||||
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR}
|
||||
${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ${max_sdk}/lib/x64/Release
|
||||
)
|
||||
|
||||
ADD_LIBRARY(IfcMax_${max_year} SHARED IfcMax.h IfcMax.cpp)
|
||||
|
||||
# TODO: find the minimal subset of 3dsmax libraries to reference
|
||||
TARGET_LINK_LIBRARIES(IfcMax_${max_year} ${IFCOPENSHELL_LIBRARIES} Comctl32.lib zlibdll.lib bmm.lib core.lib CustDlg.lib edmodel.lib expr.lib
|
||||
flt.lib geom.lib gfx.lib gup.lib imageViewers.lib ManipSys.lib maxnet.lib Maxscrpt.lib
|
||||
maxutil.lib MenuMan.lib menus.lib mesh.lib MNMath.lib Paramblk2.lib particle.lib Poly.lib RenderUtil.lib
|
||||
tessint.lib viewfile.lib ${OPENCASCADE_LIBRARIES}
|
||||
)
|
||||
|
||||
SET_TARGET_PROPERTIES(IfcMax_${max_year} PROPERTIES SUFFIX ".dli")
|
||||
|
||||
INSTALL(TARGETS IfcMax_${max_year} RUNTIME DESTINATION ${BINDIR})
|
||||
|
||||
endif()
|
||||
endforeach()
|
||||
+96
-53
@@ -17,49 +17,60 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <Max.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <stdmat.h>
|
||||
#include <istdplug.h>
|
||||
|
||||
#include "../ifcmax/IfcMax.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
#include "IfcMax.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
|
||||
static const int NUM_MATERIAL_SLOTS = 24;
|
||||
|
||||
int controlsInit = false;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) {
|
||||
BOOL WINAPI DllMain(HINSTANCE /*hinstDLL*/, ULONG /*fdwReason*/, LPVOID /*lpvReserved*/) {
|
||||
static int controlsInit = false;
|
||||
if (!controlsInit) {
|
||||
controlsInit = true;
|
||||
InitCommonControls();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
__declspec( dllexport ) const TCHAR* LibDescription() {
|
||||
return _T("IfcOpenShell IFC Importer");
|
||||
}
|
||||
|
||||
__declspec( dllexport ) int LibNumberClasses() { return 1; }
|
||||
|
||||
static class IFCImpClassDesc:public ClassDesc {
|
||||
static class IFCImpClassDesc :public ClassDesc {
|
||||
public:
|
||||
int IsPublic() {return 1;}
|
||||
void * Create(BOOL loading = FALSE) {return new IFCImp;}
|
||||
const TCHAR * ClassName() {return _T("IFCImp");}
|
||||
SClass_ID SuperClassID() {return SCENE_IMPORT_CLASS_ID;}
|
||||
Class_ID ClassID() {return Class_ID(0x3f230dbf, 0x5b3015c2);}
|
||||
const TCHAR* Category() {return _T("Chrutilities");}
|
||||
int IsPublic() { return 1; }
|
||||
void * Create(BOOL /*loading = FALSE*/) { return new IFCImp; }
|
||||
// TODO Delete() function?
|
||||
const TCHAR * ClassName() { return _T("IFCImp"); }
|
||||
SClass_ID SuperClassID() { return SCENE_IMPORT_CLASS_ID; }
|
||||
Class_ID ClassID() { return Class_ID(0x3f230dbf, 0x5b3015c2); }
|
||||
const TCHAR* Category() { return _T("Chrutilities"); }
|
||||
} IFCImpDesc;
|
||||
|
||||
__declspec( dllexport ) ClassDesc* LibClassDesc(int i) {
|
||||
return i == 0 ? &IFCImpDesc : 0;
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
|
||||
extern "C" {
|
||||
|
||||
DLLEXPORT const TCHAR* LibDescription() {
|
||||
return _T("IfcOpenShell IFC Importer");
|
||||
}
|
||||
|
||||
__declspec( dllexport ) ULONG LibVersion() {
|
||||
return VERSION_3DSMAX;
|
||||
DLLEXPORT int LibNumberClasses() { return 1; }
|
||||
|
||||
DLLEXPORT ClassDesc* LibClassDesc(int i) {
|
||||
return i == 0 ? &IFCImpDesc : 0;
|
||||
}
|
||||
|
||||
DLLEXPORT ULONG LibVersion() {
|
||||
return VERSION_3DSMAX;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int IFCImp::ExtCount() { return 1; }
|
||||
|
||||
const TCHAR * IFCImp::Ext(int n) {
|
||||
@@ -79,7 +90,7 @@ const TCHAR * IFCImp::AuthorName() {
|
||||
}
|
||||
|
||||
const TCHAR * IFCImp::CopyrightMessage() {
|
||||
return _T("Copyight (c) 2011 IfcOpenShell");
|
||||
return _T("Copyright (c) 2011-2016 IfcOpenShell");
|
||||
}
|
||||
|
||||
const TCHAR * IFCImp::OtherMessage1() {
|
||||
@@ -94,13 +105,14 @@ unsigned int IFCImp::Version() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK AboutBoxDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
return TRUE;
|
||||
}
|
||||
// TODO Use this in IFCImp::ShowAbout() if/when wanted
|
||||
//static BOOL CALLBACK AboutBoxDlgProc(HWND /*hWnd*/, UINT /*msg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) {
|
||||
// return TRUE;
|
||||
//}
|
||||
|
||||
void IFCImp::ShowAbout(HWND hWnd) {}
|
||||
void IFCImp::ShowAbout(HWND /*hWnd*/) {}
|
||||
|
||||
DWORD WINAPI fn(LPVOID arg) { return 0; }
|
||||
DWORD WINAPI fn(LPVOID /*arg*/) { return 0; }
|
||||
|
||||
#if MAX_RELEASE > 14000
|
||||
# define S(x) (TSTR::FromCStr(x.c_str()))
|
||||
@@ -110,8 +122,9 @@ DWORD WINAPI fn(LPVOID arg) { return 0; }
|
||||
# define S(x) (CStr(x.c_str()))
|
||||
#endif
|
||||
|
||||
Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
|
||||
const int mat_index = library->FindMtlByName(S(material_name));
|
||||
static Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
|
||||
TSTR mat_name = S(material_name);
|
||||
const int mat_index = library->FindMtlByName(mat_name);
|
||||
Mtl* m = 0;
|
||||
if (mat_index != -1) {
|
||||
m = static_cast<Mtl*>((*library)[mat_index]);
|
||||
@@ -119,7 +132,7 @@ Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
|
||||
return m;
|
||||
}
|
||||
|
||||
Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) {
|
||||
static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) {
|
||||
Mtl* m = FindMaterialByName(library, material.name());
|
||||
if (m == 0) {
|
||||
StdMat2* stdm = NewDefaultStdMat();
|
||||
@@ -133,10 +146,10 @@ Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& sl
|
||||
stdm->SetSpecular(Color(specular[0], specular[1], specular[2]),t);
|
||||
}
|
||||
if (material.hasSpecularity()) {
|
||||
stdm->SetShininess(material.specularity(), t);
|
||||
stdm->SetShininess((float)material.specularity(), t);
|
||||
}
|
||||
if (material.hasTransparency()) {
|
||||
stdm->SetOpacity(1.0 - material.transparency(), t);
|
||||
stdm->SetOpacity(1.0f - (float)material.transparency(), t);
|
||||
}
|
||||
m = stdm;
|
||||
m->SetName(S(material.name()));
|
||||
@@ -148,7 +161,10 @@ Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& sl
|
||||
return m;
|
||||
}
|
||||
|
||||
Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library, Interface* max_interface, int& slot, const std::vector<IfcGeom::Material>& materials, const std::string& object_type, const std::vector<int>& material_ids) {
|
||||
static Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library,
|
||||
Interface* max_interface, int& slot, const std::vector<IfcGeom::Material>& materials,
|
||||
const std::string& object_type, const std::vector<int>& material_ids)
|
||||
{
|
||||
std::vector<std::string> material_names;
|
||||
bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end();
|
||||
if (needs_default) {
|
||||
@@ -181,7 +197,7 @@ Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats,
|
||||
return i->second;
|
||||
}
|
||||
MultiMtl* multi_mat = NewDefaultMultiMtl();
|
||||
multi_mat->SetNumSubMtls(material_names.size());
|
||||
multi_mat->SetNumSubMtls((int)material_names.size());
|
||||
int mtl_id = 0;
|
||||
if (needs_default) {
|
||||
multi_mat->SetSubMtlAndName(mtl_id ++, default_material, default_material->GetName());
|
||||
@@ -198,12 +214,12 @@ Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats,
|
||||
return multi_mat;
|
||||
}
|
||||
|
||||
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) {
|
||||
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL /*suppressPrompts*/) {
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.use_world_coords() = false;
|
||||
settings.weld_vertices() = true;
|
||||
settings.sew_shells() = true;
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, true);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
|
||||
|
||||
#ifdef _UNICODE
|
||||
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
|
||||
@@ -213,9 +229,10 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
const char* fn_mb = name;
|
||||
#endif
|
||||
|
||||
IfcGeom::Iterator<float> iterator(settings, fn_mb);
|
||||
|
||||
if (!iterator.findContext()) return false;
|
||||
IfcParse::IfcFile file(fn_mb);
|
||||
IfcGeom::Iterator<float> iterator(settings, &file);
|
||||
delete fn_mb;
|
||||
if (!iterator.initialize()) return false;
|
||||
|
||||
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
|
||||
|
||||
@@ -234,28 +251,54 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
|
||||
TriObject* tri = CreateNewTriObject();
|
||||
|
||||
const int numVerts = o->geometry().verts().size()/3;
|
||||
const int numVerts = (int)o->geometry().verts().size()/3;
|
||||
tri->mesh.setNumVerts(numVerts);
|
||||
for( int i = 0; i < numVerts; i ++ ) {
|
||||
tri->mesh.setVert(i,o->geometry().verts()[3*i+0],o->geometry().verts()[3*i+1],o->geometry().verts()[3*i+2]);
|
||||
}
|
||||
const int numFaces = o->geometry().faces().size()/3;
|
||||
const int numFaces = (int)o->geometry().faces().size()/3;
|
||||
tri->mesh.setNumFaces(numFaces);
|
||||
|
||||
bool needs_default = std::find(o->geometry().material_ids().begin(), o->geometry().material_ids().end(), -1) != o->geometry().material_ids().end();
|
||||
|
||||
typedef std::pair<int, int> edge_t;
|
||||
|
||||
std::set<edge_t> face_boundaries;
|
||||
for(std::vector<int>::const_iterator it = o->geometry().edges().begin(); it != o->geometry().edges().end();) {
|
||||
const int v1 = *it++;
|
||||
const int v2 = *it++;
|
||||
|
||||
const edge_t e((std::min)(v1, v2), (std::max)(v1, v2));
|
||||
face_boundaries.insert(e);
|
||||
}
|
||||
|
||||
for( int i = 0; i < numFaces; i ++ ) {
|
||||
tri->mesh.faces[i].setVerts(o->geometry().faces()[3*i+0],o->geometry().faces()[3*i+1],o->geometry().faces()[3*i+2]);
|
||||
tri->mesh.faces[i].setEdgeVisFlags(o->geometry().edges()[3*i+0],o->geometry().edges()[3*i+1],o->geometry().edges()[3*i+2]);
|
||||
MtlID mtlid = o->geometry().material_ids()[i];
|
||||
if (needs_default) mtlid ++;
|
||||
const int v1 = o->geometry().faces()[3*i+0];
|
||||
const int v2 = o->geometry().faces()[3*i+1];
|
||||
const int v3 = o->geometry().faces()[3*i+2];
|
||||
|
||||
const edge_t e1((std::min)(v1, v2), (std::max)(v1, v2));
|
||||
const edge_t e2((std::min)(v2, v3), (std::max)(v2, v3));
|
||||
const edge_t e3((std::min)(v3, v1), (std::max)(v3, v1));
|
||||
|
||||
const bool b1 = face_boundaries.find(e1) != face_boundaries.end();
|
||||
const bool b2 = face_boundaries.find(e2) != face_boundaries.end();
|
||||
const bool b3 = face_boundaries.find(e3) != face_boundaries.end();
|
||||
|
||||
tri->mesh.faces[i].setVerts(v1, v2, v3);
|
||||
tri->mesh.faces[i].setEdgeVisFlags(b1, b2, b3);
|
||||
|
||||
MtlID mtlid = (MtlID)o->geometry().material_ids()[i];
|
||||
if (needs_default) {
|
||||
mtlid ++;
|
||||
}
|
||||
tri->mesh.faces[i].setMatID(mtlid);
|
||||
}
|
||||
|
||||
tri->mesh.buildNormals();
|
||||
// Either use this or undefine the FACESETS_AS_COMPOUND option in IfcGeom.h to have
|
||||
// properly oriented normals. Using only the line below will result in a consistent
|
||||
// orientation of normals accross shells, but not always oriented towards the
|
||||
// orientation of normals across shells, but not always oriented towards the
|
||||
// outside.
|
||||
// tri->mesh.UnifyNormals(false);
|
||||
tri->mesh.BuildStripsAndEdges();
|
||||
@@ -281,4 +324,4 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
itfc->ProgressEnd();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
LIBRARY ifcmax.dli
|
||||
EXPORTS
|
||||
LibDescription @1
|
||||
LibNumberClasses @2
|
||||
LibClassDesc @3
|
||||
LibVersion @4
|
||||
SECTIONS
|
||||
.data READ WRITE
|
||||
+1
-7
@@ -21,12 +21,6 @@
|
||||
#define IFCMAX_H
|
||||
|
||||
#include "Max.h"
|
||||
#include "istdplug.h"
|
||||
#include "stdmat.h"
|
||||
#include "decomp.h"
|
||||
#include "shape.h"
|
||||
#include "splshape.h"
|
||||
#include "dummy.h"
|
||||
|
||||
extern ClassDesc* GetIFCImpDesc();
|
||||
|
||||
@@ -38,7 +32,7 @@ public:
|
||||
const TCHAR * LongDesc(); // = "IfcOpenShell IFC Importer for 3ds Max"
|
||||
const TCHAR * ShortDesc(); // = "Industry Foundation Classes"
|
||||
const TCHAR * AuthorName(); // = "Thomas Krijnen"
|
||||
const TCHAR * CopyrightMessage(); // = "Copyight (c) 2011 IfcOpenShell"
|
||||
const TCHAR * CopyrightMessage(); // = "Copyright (c) 2011-2016 IfcOpenShell"
|
||||
const TCHAR * OtherMessage1(); // = ""
|
||||
const TCHAR * OtherMessage2(); // = ""
|
||||
unsigned int Version(); // = 12
|
||||
|
||||
@@ -17,117 +17,62 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import platform
|
||||
import functools
|
||||
import itertools
|
||||
|
||||
from functools import reduce
|
||||
if hasattr(os, 'uname'):
|
||||
platform_system = os.uname()[0].lower()
|
||||
else:
|
||||
platform_system = 'windows'
|
||||
|
||||
from . import guid
|
||||
if sys.maxsize == (1 << 31) - 1:
|
||||
platform_architecture = '32bit'
|
||||
else:
|
||||
platform_architecture = '64bit'
|
||||
|
||||
python_distribution = os.path.join(platform.system().lower(),
|
||||
platform.architecture()[0],
|
||||
'python%s.%s' % platform.python_version_tuple()[:2])
|
||||
python_version_tuple = tuple(sys.version.split(' ')[0].split('.'))
|
||||
|
||||
python_distribution = os.path.join(platform_system,
|
||||
platform_architecture,
|
||||
'python%s.%s' % python_version_tuple[:2])
|
||||
sys.path.append(os.path.abspath(os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'lib', python_distribution)))
|
||||
os.path.dirname(__file__),
|
||||
'lib', python_distribution)))
|
||||
|
||||
try:
|
||||
from . import ifcopenshell_wrapper
|
||||
except:
|
||||
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
|
||||
from . import ifcopenshell_wrapper
|
||||
except Exception as e:
|
||||
if int(python_version_tuple[0]) == 2:
|
||||
# Only for py2, as py3 has exception chaining
|
||||
import traceback
|
||||
|
||||
class entity_instance(object):
|
||||
def __init__(self, e):
|
||||
super(entity_instance, self).__setattr__('wrapped_data', e)
|
||||
def __getattr__(self, name):
|
||||
try: return entity_instance.wrap_value(self.wrapped_data.get_argument(self.wrapped_data.get_argument_index(name)))
|
||||
except:
|
||||
try: return entity_instance.wrap_value(self.wrapped_data.get_inverse(name))
|
||||
except: raise AttributeError("entity instance of type '%s' has no attribute '%s'"%(self.wrapped_data.is_a(), name))
|
||||
@staticmethod
|
||||
def map_value(v):
|
||||
if isinstance(v, entity_instance): return v.wrapped_data
|
||||
elif isinstance(v, (tuple, list)) and len(v):
|
||||
classes = list(map(type, v))
|
||||
if float in classes: return ifcopenshell_wrapper.double_vector(v)
|
||||
elif int in classes: return ifcopenshell_wrapper.int_vector(v)
|
||||
elif str in classes: return ifcopenshell_wrapper.string_vector(v)
|
||||
elif entity_instance in classes: return list(map(lambda e: e.wrapped_data, v))
|
||||
return v
|
||||
@staticmethod
|
||||
def wrap_value(v):
|
||||
wrap = lambda e: entity_instance(e)
|
||||
if isinstance(v, ifcopenshell_wrapper.entity_instance): return wrap(v)
|
||||
elif isinstance(v, (tuple, list)) and len(v):
|
||||
classes = list(map(type, v))
|
||||
if ifcopenshell_wrapper.entity_instance in classes: return list(map(wrap, v))
|
||||
return v
|
||||
def attribute_type(self, attr):
|
||||
attr_idx = attr if isinstance(attr, int) else self.wrapped_data.get_argument_index(attr)
|
||||
return self.wrapped_data.get_argument_type(attr_idx)
|
||||
def attribute_name(self, attr_idx):
|
||||
return self.wrapped_data.get_argument_name(attr_idx)
|
||||
def __setattr__(self, key, value):
|
||||
self[self.wrapped_data.get_argument_index(key)] = value
|
||||
def __getitem__(self, key):
|
||||
return entity_instance.wrap_value(self.wrapped_data.get_argument(key))
|
||||
def __setitem__(self, idx, value):
|
||||
self.wrapped_data.set_argument(idx, entity_instance.map_value(value))
|
||||
def __len__(self): return len(self.wrapped_data)
|
||||
def __repr__(self): return repr(self.wrapped_data)
|
||||
def is_a(self, *args): return self.wrapped_data.is_a(*args)
|
||||
def id(self): return self.wrapped_data.id()
|
||||
def __dir__(self):
|
||||
return sorted(set(itertools.chain(
|
||||
dir(type(self)),
|
||||
self.wrapped_data.get_attribute_names(),
|
||||
self.wrapped_data.get_inverse_attribute_names()
|
||||
)))
|
||||
traceback.print_exc()
|
||||
print('-' * 64)
|
||||
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
|
||||
|
||||
from . import guid
|
||||
from .file import file
|
||||
from .entity_instance import entity_instance
|
||||
|
||||
|
||||
class file(object):
|
||||
def __init__(self, f=None):
|
||||
self.wrapped_data = f or ifcopenshell_wrapper.file(True)
|
||||
def create_entity(self,type,*args,**kwargs):
|
||||
e = entity_instance(ifcopenshell_wrapper.entity_instance(type))
|
||||
attrs = list(enumerate(args)) + \
|
||||
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
||||
for idx, arg in attrs: e[idx] = arg
|
||||
self.wrapped_data.add(e.wrapped_data)
|
||||
e.wrapped_data.this.disown()
|
||||
return e
|
||||
def __getattr__(self, attr):
|
||||
if attr[0:6] == 'create': return functools.partial(self.create_entity,attr[6:])
|
||||
else: return getattr(self.wrapped_data, attr)
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, int):
|
||||
return entity_instance(self.wrapped_data.by_id(key))
|
||||
elif isinstance(key, str):
|
||||
return entity_instance(self.wrapped_data.by_guid(key))
|
||||
def add(self, inst):
|
||||
inst.wrapped_data.this.disown()
|
||||
return entity_instance(self.wrapped_data.add(inst.wrapped_data))
|
||||
def by_type(self, type):
|
||||
return [entity_instance(e) for e in self.wrapped_data.by_type(type)]
|
||||
def traverse(self, inst):
|
||||
return [entity_instance(e) for e in self.wrapped_data.traverse(inst.wrapped_data)]
|
||||
def remove(self, inst):
|
||||
return self.wrapped_data.remove(inst.wrapped_data)
|
||||
def __iter__(self):
|
||||
return iter(self[id] for id in self.wrapped_data.entity_names())
|
||||
def open(fn):
|
||||
f = ifcopenshell_wrapper.open(os.path.abspath(fn))
|
||||
if f.good():
|
||||
return file(f)
|
||||
else:
|
||||
raise IOError("Unable to open file for reading")
|
||||
|
||||
def create_entity(type, *args, **kwargs):
|
||||
e = entity_instance(type)
|
||||
attrs = list(enumerate(args)) + \
|
||||
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
||||
for idx, arg in attrs:
|
||||
e[idx] = arg
|
||||
return e
|
||||
|
||||
|
||||
def open(fn=None):
|
||||
return file(ifcopenshell_wrapper.open(os.path.abspath(fn))) if fn else file()
|
||||
|
||||
|
||||
def create_entity(type,*args,**kwargs):
|
||||
e = entity_instance(ifcopenshell_wrapper.entity_instance(type))
|
||||
attrs = list(enumerate(args)) + \
|
||||
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
||||
for idx, arg in attrs: e[idx] = arg
|
||||
return e
|
||||
|
||||
from .main import *
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import functools
|
||||
import numbers
|
||||
import itertools
|
||||
|
||||
from . import ifcopenshell_wrapper
|
||||
|
||||
try:
|
||||
import logging
|
||||
except ImportError as e:
|
||||
logging = type('logger', (object,), {'exception': staticmethod(lambda s: print(s))})
|
||||
|
||||
|
||||
class entity_instance(object):
|
||||
"""
|
||||
This is the base python class for all IFC objects.
|
||||
|
||||
An instantiated entity_instance will have methods of Python and the IFC class itself.
|
||||
|
||||
example:
|
||||
|
||||
ifc_file = ifcopenshell.open(file_path)
|
||||
products = ifc_file.by_type("IfcProduct")
|
||||
|
||||
print(products[0].__class__)
|
||||
>>> <class 'ifcopenshell.entity_instance.entity_instance'>
|
||||
|
||||
print(products[0].Representation)
|
||||
>>> #423=IfcProductDefinitionShape($,$,(#409,#421))
|
||||
"""
|
||||
def __init__(self, e):
|
||||
if isinstance(e, tuple):
|
||||
e = ifcopenshell_wrapper.new_IfcBaseClass(*e)
|
||||
super(entity_instance, self).__setattr__('wrapped_data', e)
|
||||
|
||||
def __getattr__(self, name):
|
||||
INVALID, FORWARD, INVERSE = range(3)
|
||||
attr_cat = self.wrapped_data.get_attribute_category(name)
|
||||
if attr_cat == FORWARD:
|
||||
return entity_instance.wrap_value(
|
||||
self.wrapped_data.get_argument(self.wrapped_data.get_argument_index(name)))
|
||||
elif attr_cat == INVERSE:
|
||||
return entity_instance.wrap_value(self.wrapped_data.get_inverse(name))
|
||||
else:
|
||||
raise AttributeError(
|
||||
"entity instance of type '%s' has no attribute '%s'" % (self.wrapped_data.is_a(), name))
|
||||
|
||||
@staticmethod
|
||||
def walk(f, g, value):
|
||||
if isinstance(value, (tuple, list)):
|
||||
return tuple(map(functools.partial(entity_instance.walk, f, g), value))
|
||||
elif f(value):
|
||||
return g(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def wrap_value(v):
|
||||
def wrap(e): return entity_instance(e)
|
||||
|
||||
def is_instance(e): return isinstance(e, ifcopenshell_wrapper.entity_instance)
|
||||
|
||||
return entity_instance.walk(is_instance, wrap, v)
|
||||
|
||||
@staticmethod
|
||||
def unwrap_value(v):
|
||||
def unwrap(e): return e.wrapped_data
|
||||
|
||||
def is_instance(e): return isinstance(e, entity_instance)
|
||||
|
||||
return entity_instance.walk(is_instance, unwrap, v)
|
||||
|
||||
def attribute_type(self, attr):
|
||||
attr_idx = attr if isinstance(attr, numbers.Integral) else self.wrapped_data.get_argument_index(attr)
|
||||
return self.wrapped_data.get_argument_type(attr_idx)
|
||||
|
||||
def attribute_name(self, attr_idx):
|
||||
return self.wrapped_data.get_argument_name(attr_idx)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
self[self.wrapped_data.get_argument_index(key)] = value
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key < 0 or key >= len(self):
|
||||
raise IndexError("Attribute index {} out of range for instance of type {}".format(key, self.is_a()))
|
||||
return entity_instance.wrap_value(self.wrapped_data.get_argument(key))
|
||||
|
||||
def __setitem__(self, idx, value):
|
||||
attr_type = real_attr_type = self.attribute_type(idx).title().replace(' ', '')
|
||||
real_attr_type = real_attr_type.replace('Derived', 'None')
|
||||
attr_type = attr_type.replace('Binary', 'String')
|
||||
attr_type = attr_type.replace('Enumeration', 'String')
|
||||
|
||||
if value is None:
|
||||
if attr_type != "Derived":
|
||||
self.wrapped_data.setArgumentAsNull(idx)
|
||||
else:
|
||||
valid = attr_type != "Derived"
|
||||
if valid:
|
||||
try:
|
||||
if isinstance(value, unicode):
|
||||
value = value.encode("utf-8")
|
||||
except BaseException:
|
||||
pass
|
||||
|
||||
try:
|
||||
if attr_type != "Derived":
|
||||
getattr(self.wrapped_data, "setArgumentAs%s" % attr_type)(idx, entity_instance.unwrap_value(value))
|
||||
except BaseException as e:
|
||||
valid = False
|
||||
|
||||
if not valid:
|
||||
raise ValueError("Expected %s for attribute %s.%s, got %r" % (
|
||||
real_attr_type, self.is_a(), self.attribute_name(idx), value))
|
||||
|
||||
return value
|
||||
|
||||
def __len__(self):
|
||||
return len(self.wrapped_data)
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.wrapped_data)
|
||||
|
||||
def is_a(self, *args):
|
||||
return self.wrapped_data.is_a(*args)
|
||||
|
||||
def id(self):
|
||||
return self.wrapped_data.id()
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(self, type(other)):
|
||||
return False
|
||||
return self.wrapped_data == other.wrapped_data
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.id(), self.wrapped_data.file_pointer()))
|
||||
|
||||
def __dir__(self):
|
||||
return sorted(set(itertools.chain(
|
||||
dir(type(self)),
|
||||
map(str, self.wrapped_data.get_attribute_names()),
|
||||
map(str, self.wrapped_data.get_inverse_attribute_names())
|
||||
)))
|
||||
|
||||
def get_info(self, include_identifier=True, recursive=False, return_type=dict, ignore=()):
|
||||
"""
|
||||
Return a dictionary of the entity_instance's properties (Python and IFC) and their values.
|
||||
|
||||
example:
|
||||
|
||||
ifc_file = ifcopenshell.open(file_path)
|
||||
products = ifc_file.by_type("IfcProduct")
|
||||
obj_info = products[0].get_info()
|
||||
print(obj_info.keys())
|
||||
|
||||
>>> dict_keys(['Description', 'Name', 'BuildingAddress', 'LongName', 'GlobalId', 'ObjectPlacement', 'OwnerHistory', 'ObjectType',
|
||||
>>> ...'ElevationOfTerrain', 'CompositionType', 'id', 'Representation', 'type', 'ElevationOfRefHeight'])
|
||||
"""
|
||||
def _():
|
||||
try:
|
||||
if include_identifier:
|
||||
yield "id", self.id()
|
||||
yield "type", self.is_a()
|
||||
except BaseException:
|
||||
logging.exception("unhandled exception while getting id / type info on {}".format(self))
|
||||
for i in range(len(self)):
|
||||
try:
|
||||
if self.wrapped_data.get_attribute_names()[i] in ignore:
|
||||
continue
|
||||
attr_value = self[i]
|
||||
if recursive:
|
||||
def is_instance(e): return isinstance(e, entity_instance)
|
||||
|
||||
def get_info_(inst):
|
||||
# for ty in ignore:
|
||||
# if inst.is_a(ty):
|
||||
# return None
|
||||
return entity_instance.get_info(inst,
|
||||
include_identifier=include_identifier,
|
||||
recursive=recursive,
|
||||
return_type=return_type,
|
||||
ignore=ignore
|
||||
)
|
||||
|
||||
attr_value = entity_instance.walk(is_instance, get_info_, attr_value)
|
||||
yield self.attribute_name(i), attr_value
|
||||
except BaseException:
|
||||
logging.exception("unhandled exception occurred setting attribute name for {}".format(self))
|
||||
|
||||
return return_type(_())
|
||||
|
||||
__dict__ = property(get_info)
|
||||
@@ -0,0 +1,132 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import numbers
|
||||
import functools
|
||||
|
||||
from . import ifcopenshell_wrapper
|
||||
from .entity_instance import entity_instance
|
||||
|
||||
try:
|
||||
# Python 2
|
||||
basestring
|
||||
except NameError:
|
||||
# Python 3 or newer
|
||||
basestring = (str, bytes)
|
||||
|
||||
|
||||
class file(object):
|
||||
"""
|
||||
Base class for containing IFC files.
|
||||
|
||||
Class has instance methods for filtering by element Id, Type, etc.
|
||||
|
||||
Instantiated objects can be subscripted by Id or Guid
|
||||
|
||||
example:
|
||||
|
||||
ifc_file = ifcopenshell.open(file_path)
|
||||
products = ifc_file.by_type("IfcProduct")
|
||||
|
||||
print(products[0].id(), products[0].GlobalId)
|
||||
>>> 122 2XQ$n5SLP5MBLyL442paFx
|
||||
|
||||
# Subscripting
|
||||
print(products[0] == ifc_file[122] == ifc_file['2XQ$n5SLP5MBLyL442paFx'])
|
||||
>>> True
|
||||
"""
|
||||
def __init__(self, f=None, schema=None):
|
||||
if f is not None:
|
||||
self.wrapped_data = f
|
||||
else:
|
||||
args = filter(None, [schema])
|
||||
args = map(ifcopenshell_wrapper.schema_by_name, args)
|
||||
self.wrapped_data = ifcopenshell_wrapper.file(*args)
|
||||
|
||||
def create_entity(self, type, *args, **kwargs):
|
||||
e = entity_instance((self.schema, type))
|
||||
self.wrapped_data.add(e.wrapped_data)
|
||||
e.wrapped_data.this.disown()
|
||||
attrs = list(enumerate(args)) + \
|
||||
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
||||
for idx, arg in attrs:
|
||||
e[idx] = arg
|
||||
return e
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr[0:6] == 'create':
|
||||
return functools.partial(self.create_entity, attr[6:])
|
||||
else:
|
||||
return getattr(self.wrapped_data, attr)
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, numbers.Integral):
|
||||
return entity_instance(self.wrapped_data.by_id(key))
|
||||
elif isinstance(key, basestring):
|
||||
return entity_instance(self.wrapped_data.by_guid(str(key)))
|
||||
|
||||
def by_id(self, id):
|
||||
"""
|
||||
Return IFC objects filtered by IFC ID.
|
||||
|
||||
Returned objects are unwrapped IFC objects.
|
||||
"""
|
||||
return self[id]
|
||||
|
||||
def by_guid(self, guid):
|
||||
"""
|
||||
Return IFC objects filtered by IFC GUID.
|
||||
|
||||
Returned objects are unwrapped IFC objects.
|
||||
"""
|
||||
return self[guid]
|
||||
|
||||
def add(self, inst):
|
||||
inst.wrapped_data.this.disown()
|
||||
return entity_instance(self.wrapped_data.add(inst.wrapped_data))
|
||||
|
||||
def by_type(self, type):
|
||||
"""
|
||||
Return IFC objects filtered by IFC Type and wrapped with the entity_instance class.
|
||||
|
||||
See ifcopenshell.entity_instance for class methods and properties
|
||||
"""
|
||||
return [entity_instance(e) for e in self.wrapped_data.by_type(type)]
|
||||
|
||||
def traverse(self, inst, max_levels=None):
|
||||
if max_levels is None:
|
||||
max_levels = -1
|
||||
return [entity_instance(e) for e in self.wrapped_data.traverse(inst.wrapped_data, max_levels)]
|
||||
|
||||
def get_inverse(self, inst):
|
||||
return [entity_instance(e) for e in self.wrapped_data.get_inverse(inst.wrapped_data)]
|
||||
|
||||
def remove(self, inst):
|
||||
return self.wrapped_data.remove(inst.wrapped_data)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self[id] for id in self.wrapped_data.entity_names())
|
||||
|
||||
@staticmethod
|
||||
def from_string(s):
|
||||
return file(ifcopenshell_wrapper.read(s))
|
||||
@@ -17,66 +17,9 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from .. import ifcopenshell_wrapper
|
||||
|
||||
def has_occ():
|
||||
try: import OCC.BRepTools
|
||||
except: return False
|
||||
return True
|
||||
|
||||
|
||||
has_occ = has_occ()
|
||||
wrap_shape_creation = lambda settings, shape: shape
|
||||
if has_occ:
|
||||
import occ_utils as utils
|
||||
wrap_shape_creation = lambda settings, shape: utils.create_shape_from_serialization(shape) if getattr(settings, 'use_python_opencascade', False) else shape
|
||||
|
||||
|
||||
# Subclass the settings module to provide an additional
|
||||
# setting to enable pythonOCC when available
|
||||
class settings(ifcopenshell_wrapper.settings):
|
||||
if has_occ:
|
||||
USE_PYTHON_OPENCASCADE = -1
|
||||
def set(self, *args):
|
||||
setting, value = args
|
||||
if setting == settings.USE_PYTHON_OPENCASCADE:
|
||||
self.set(settings.USE_BREP_DATA, value)
|
||||
self.set(settings.USE_WORLD_COORDS, value)
|
||||
self.set(settings.DISABLE_TRIANGULATION, value)
|
||||
self.use_python_opencascade = value
|
||||
else:
|
||||
ifcopenshell_wrapper.settings.set(self, *args)
|
||||
|
||||
|
||||
# Hide templating precision to the user by choosing based on Python's
|
||||
# internal float type. This is probably always going to be a double.
|
||||
for ty in (ifcopenshell_wrapper.iterator_single_precision, ifcopenshell_wrapper.iterator_double_precision):
|
||||
if ty.mantissa_size() == sys.float_info.mant_dig:
|
||||
_iterator = ty
|
||||
|
||||
|
||||
# Make sure people are able to use python's platform agnostic paths
|
||||
class iterator(_iterator):
|
||||
def __init__(self, settings, filename):
|
||||
self.settings = settings
|
||||
_iterator.__init__(self, settings, os.path.abspath(filename))
|
||||
if has_occ:
|
||||
def get(self):
|
||||
return wrap_shape_creation(self.settings, _iterator.get(self))
|
||||
|
||||
|
||||
def create_shape(settings, inst):
|
||||
return wrap_shape_creation(settings, ifcopenshell_wrapper.create_shape(settings, inst.wrapped_data))
|
||||
|
||||
|
||||
def iterate(settings, filename):
|
||||
it = iterator(settings, filename)
|
||||
if it.findContext():
|
||||
while True:
|
||||
yield it.get()
|
||||
if not it.next(): break
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from . import occ_utils as utils
|
||||
from .main import *
|
||||
|
||||
@@ -0,0 +1,611 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import operator
|
||||
import functools
|
||||
|
||||
import OCC.AIS
|
||||
|
||||
from collections import defaultdict, Iterable, OrderedDict
|
||||
|
||||
try:
|
||||
QString = unicode
|
||||
except NameError:
|
||||
# Python 3
|
||||
QString = str
|
||||
|
||||
os.environ['QT_API'] = 'pyqt5'
|
||||
try:
|
||||
from pyqode.qt import QtCore
|
||||
except BaseException:
|
||||
pass
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from .code_editor_pane import code_edit
|
||||
|
||||
try:
|
||||
from OCC.Display.pyqt5Display import qtViewer3d
|
||||
except BaseException:
|
||||
import OCC.Display
|
||||
|
||||
try:
|
||||
import OCC.Display.backend
|
||||
except BaseException:
|
||||
pass
|
||||
|
||||
try:
|
||||
OCC.Display.backend.get_backend("qt-pyqt5")
|
||||
except BaseException:
|
||||
OCC.Display.backend.load_backend("qt-pyqt5")
|
||||
|
||||
from OCC.Display.qtDisplay import qtViewer3d
|
||||
|
||||
from .main import settings, iterator
|
||||
from .occ_utils import display_shape
|
||||
|
||||
from .. import open as open_ifc_file
|
||||
from .. import version as ifcopenshell_version
|
||||
|
||||
if ifcopenshell_version < "0.6":
|
||||
# not yet ported
|
||||
from .. import get_supertype
|
||||
|
||||
class configuration(object):
|
||||
def __init__(self):
|
||||
try:
|
||||
import ConfigParser
|
||||
Cfg = ConfigParser.RawConfigParser
|
||||
except BaseException:
|
||||
import configparser
|
||||
|
||||
def Cfg():
|
||||
return configparser.ConfigParser(interpolation=None)
|
||||
|
||||
conf_file = os.path.expanduser(os.path.join("~", ".ifcopenshell", "app", "snippets.conf"))
|
||||
if conf_file.startswith("~"):
|
||||
conf_file = None
|
||||
return
|
||||
|
||||
self.config_encode = lambda s: s.replace("\\", "\\\\").replace("\n", "\n|")
|
||||
self.config_decode = lambda s: s.replace("\n|", "\n").replace("\\\\", "\\")
|
||||
|
||||
if not os.path.exists(os.path.dirname(conf_file)):
|
||||
os.makedirs(os.path.dirname(conf_file))
|
||||
|
||||
if not os.path.exists(conf_file):
|
||||
config = Cfg()
|
||||
config.add_section("snippets")
|
||||
config.set("snippets", "print all wall ids", self.config_encode("""
|
||||
###########################################################################
|
||||
# A simple script that iterates over all walls in the current model #
|
||||
# and prints their Globally unique IDs (GUIDS) to the console window #
|
||||
###########################################################################
|
||||
|
||||
for wall in model.by_type("IfcWall"):
|
||||
print ("wall with global id: "+str(wall.GlobalId))
|
||||
""".lstrip()))
|
||||
|
||||
config.set("snippets", "print properties of current selection", self.config_encode("""
|
||||
###########################################################################
|
||||
# A simple script that iterates over all IfcPropertySets of the currently #
|
||||
# selected object and prints them to the console #
|
||||
###########################################################################
|
||||
|
||||
# check if something is selected
|
||||
if selection:
|
||||
#get the IfcProduct that is stored in the global variable 'selection'
|
||||
obj = selection
|
||||
for relDefinesByProperties in obj.IsDefinedBy:
|
||||
print("[{0}]".format(relDefinesByProperties.RelatingPropertyDefinition.Name))
|
||||
for prop in relDefinesByProperties.RelatingPropertyDefinition.HasProperties:
|
||||
print ("{:<20} :{}".format(prop.Name,prop.NominalValue.wrappedValue))
|
||||
print ("\\n")
|
||||
""".lstrip()))
|
||||
with open(conf_file, 'w') as configfile:
|
||||
config.write(configfile)
|
||||
|
||||
self.config = Cfg()
|
||||
self.config.read(conf_file)
|
||||
|
||||
def options(self, s):
|
||||
return OrderedDict([(k, self.config_decode(self.config.get(s, k))) for k in self.config.options(s)])
|
||||
|
||||
|
||||
class application(QtWidgets.QApplication):
|
||||
"""A pythonOCC, PyQt based IfcOpenShell application
|
||||
with two tree views and a graphical 3d view"""
|
||||
|
||||
class abstract_treeview(QtWidgets.QTreeWidget):
|
||||
|
||||
"""Base class for the two treeview controls"""
|
||||
|
||||
instanceSelected = QtCore.pyqtSignal([object])
|
||||
instanceVisibilityChanged = QtCore.pyqtSignal([object, int])
|
||||
instanceDisplayModeChanged = QtCore.pyqtSignal([object, int])
|
||||
|
||||
def __init__(self):
|
||||
QtWidgets.QTreeView.__init__(self)
|
||||
self.setColumnCount(len(self.ATTRIBUTES))
|
||||
self.setHeaderLabels(self.ATTRIBUTES)
|
||||
self.children = defaultdict(list)
|
||||
|
||||
def get_children(self, inst):
|
||||
c = [inst]
|
||||
i = 0
|
||||
while i < len(c):
|
||||
c.extend(self.children[c[i]])
|
||||
i += 1
|
||||
return c
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
menu = QtWidgets.QMenu(self)
|
||||
visibility = [menu.addAction("Show"), menu.addAction("Hide")]
|
||||
displaymode = [menu.addAction("Solid"), menu.addAction("Wireframe")]
|
||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||
index = self.selectionModel().currentIndex()
|
||||
inst = index.data(QtCore.Qt.UserRole)
|
||||
if hasattr(inst, 'toPyObject'):
|
||||
inst = inst
|
||||
if action in visibility:
|
||||
self.instanceVisibilityChanged.emit(inst, visibility.index(action))
|
||||
elif action in displaymode:
|
||||
self.instanceDisplayModeChanged.emit(inst, displaymode.index(action))
|
||||
|
||||
def clicked_(self, index):
|
||||
inst = index.data(QtCore.Qt.UserRole)
|
||||
if hasattr(inst, 'toPyObject'):
|
||||
inst = inst
|
||||
if inst:
|
||||
self.instanceSelected.emit(inst)
|
||||
|
||||
def select(self, product):
|
||||
itm = self.product_to_item.get(product)
|
||||
if itm is None:
|
||||
return
|
||||
self.selectionModel().setCurrentIndex(itm,
|
||||
QtCore.QItemSelectionModel.SelectCurrent | QtCore.QItemSelectionModel.Rows)
|
||||
|
||||
class decomposition_treeview(abstract_treeview):
|
||||
|
||||
"""Treeview with typical IFC decomposition relationships"""
|
||||
|
||||
ATTRIBUTES = ['Entity', 'GlobalId', 'Name']
|
||||
|
||||
def parent(self, instance):
|
||||
if instance.is_a("IfcOpeningElement"):
|
||||
return instance.VoidsElements[0].RelatingBuildingElement
|
||||
if instance.is_a("IfcElement"):
|
||||
fills = instance.FillsVoids
|
||||
if len(fills):
|
||||
return fills[0].RelatingOpeningElement
|
||||
containments = instance.ContainedInStructure
|
||||
if len(containments):
|
||||
return containments[0].RelatingStructure
|
||||
if instance.is_a("IfcObjectDefinition"):
|
||||
decompositions = instance.Decomposes
|
||||
if len(decompositions):
|
||||
return decompositions[0].RelatingObject
|
||||
|
||||
def load_file(self, f, **kwargs):
|
||||
products = list(f.by_type("IfcProduct")) + list(f.by_type("IfcProject"))
|
||||
parents = list(map(self.parent, products))
|
||||
items = {}
|
||||
skipped = 0
|
||||
ATTRS = self.ATTRIBUTES
|
||||
while len(items) + skipped < len(products):
|
||||
for product, parent in zip(products, parents):
|
||||
if parent is None and not product.is_a("IfcProject"):
|
||||
skipped += 1
|
||||
continue
|
||||
if (parent is None or parent in items) and product not in items:
|
||||
sl = []
|
||||
for attr in ATTRS:
|
||||
if attr == 'Entity':
|
||||
sl.append(product.is_a())
|
||||
else:
|
||||
sl.append(getattr(product, attr) or '')
|
||||
itm = items[product] = QtWidgets.QTreeWidgetItem(items.get(parent, self), sl)
|
||||
itm.setData(0, QtCore.Qt.UserRole, product)
|
||||
self.children[parent].append(product)
|
||||
self.product_to_item = dict(zip(items.keys(), map(self.indexFromItem, items.values())))
|
||||
self.clicked.connect(self.clicked_)
|
||||
self.expandAll()
|
||||
|
||||
class type_treeview(abstract_treeview):
|
||||
|
||||
"""Treeview with typical IFC decomposition relationships"""
|
||||
|
||||
ATTRIBUTES = ['Name']
|
||||
|
||||
def load_file(self, f, **kwargs):
|
||||
products = list(f.by_type("IfcProduct"))
|
||||
types = set(map(lambda i: i.is_a(), products))
|
||||
items = {}
|
||||
for t in types:
|
||||
def add(t):
|
||||
s = get_supertype(t)
|
||||
if s:
|
||||
add(s)
|
||||
s2, t2 = map(QString, (s, t))
|
||||
if t2 not in items:
|
||||
itm = items[t2] = QtWidgets.QTreeWidgetItem(items.get(s2, self), [t2])
|
||||
itm.setData(0, QtCore.Qt.UserRole, t2)
|
||||
self.children[s2].append(t2)
|
||||
|
||||
if ifcopenshell_version < "0.6":
|
||||
add(t)
|
||||
|
||||
for p in products:
|
||||
t = QString(p.is_a())
|
||||
itm = items[p] = QtWidgets.QTreeWidgetItem(items.get(t, self), [p.Name or '<no name>'])
|
||||
itm.setData(0, QtCore.Qt.UserRole, t)
|
||||
self.children[t].append(p)
|
||||
|
||||
self.product_to_item = dict(zip(items.keys(), map(self.indexFromItem, items.values())))
|
||||
self.clicked.connect(self.clicked)
|
||||
self.expandAll()
|
||||
|
||||
class property_table(QtWidgets.QWidget):
|
||||
|
||||
def __init__(self):
|
||||
QtWidgets.QWidget.__init__(self)
|
||||
self.layout = QtWidgets.QVBoxLayout(self)
|
||||
self.setLayout(self.layout)
|
||||
self.scroll = QtWidgets.QScrollArea(self)
|
||||
self.layout.addWidget(self.scroll)
|
||||
self.scroll.setWidgetResizable(True)
|
||||
self.scrollContent = QtWidgets.QWidget(self.scroll)
|
||||
self.scrollLayout = QtWidgets.QVBoxLayout(self.scrollContent)
|
||||
self.scrollContent.setLayout(self.scrollLayout)
|
||||
self.scroll.setWidget(self.scrollContent)
|
||||
self.prop_dict = {}
|
||||
|
||||
# triggered by selection event in either component of parent
|
||||
def select(self, product):
|
||||
|
||||
# Clear the old contents if any
|
||||
while self.scrollLayout.count():
|
||||
child = self.scrollLayout.takeAt(0)
|
||||
if child is not None:
|
||||
if child.widget() is not None:
|
||||
child.widget().deleteLater()
|
||||
|
||||
self.scroll = QtWidgets.QScrollArea()
|
||||
self.scroll.setWidgetResizable(True)
|
||||
|
||||
prop_sets = self.prop_dict.get(str(product))
|
||||
|
||||
if prop_sets is not None:
|
||||
for k, v in prop_sets:
|
||||
group_box = QtWidgets.QGroupBox()
|
||||
|
||||
group_box.setTitle(k)
|
||||
group_layout = QtWidgets.QVBoxLayout()
|
||||
group_box.setLayout(group_layout)
|
||||
|
||||
for name, value in v.items():
|
||||
prop_name = str(name)
|
||||
|
||||
value_str = value
|
||||
if hasattr(value_str, "wrappedValue"):
|
||||
value_str = value_str.wrappedValue
|
||||
|
||||
if isinstance(value_str, unicode):
|
||||
value_str = value_str.encode('utf-8')
|
||||
else:
|
||||
value_str = str(value_str)
|
||||
|
||||
if hasattr(value, "is_a"):
|
||||
type_str = " <i>(%s)</i>" % value.is_a()
|
||||
else:
|
||||
type_str = ""
|
||||
label = QtWidgets.QLabel("<b>%s</b>: %s%s" % (prop_name, value_str, type_str))
|
||||
group_layout.addWidget(label)
|
||||
|
||||
group_layout.addStretch()
|
||||
self.scrollLayout.addWidget(group_box)
|
||||
|
||||
self.scrollLayout.addStretch()
|
||||
else:
|
||||
label = QtWidgets.QLabel("No IfcPropertySets asscociated with selected entity instance")
|
||||
self.scrollLayout.addWidget(label)
|
||||
|
||||
def load_file(self, f, **kwargs):
|
||||
for p in f.by_type("IfcProduct"):
|
||||
propsets = []
|
||||
|
||||
def process_pset(prop_def):
|
||||
if prop_def is not None:
|
||||
prop_set_name = prop_def.Name
|
||||
props = {}
|
||||
if prop_def.is_a("IfcElementQuantity"):
|
||||
for q in prop_def.Quantities:
|
||||
if q.is_a("IfcPhysicalSimpleQuantity"):
|
||||
props[q.Name] = q[3]
|
||||
elif prop_def.is_a("IfcPropertySet"):
|
||||
for prop in prop_def.HasProperties:
|
||||
if prop.is_a("IfcPropertySingleValue"):
|
||||
props[prop.Name] = prop.NominalValue
|
||||
else:
|
||||
# Entity introduced in IFC4
|
||||
# prop_def.is_a("IfcPreDefinedPropertySet"):
|
||||
for prop in range(4, len(prop_def)):
|
||||
props[prop_def.attribute_name(prop)] = prop_def[prop]
|
||||
return prop_set_name, props
|
||||
|
||||
try:
|
||||
for is_def_by in p.IsDefinedBy:
|
||||
if is_def_by.is_a("IfcRelDefinesByProperties"):
|
||||
propsets.append(process_pset(is_def_by.RelatingPropertyDefinition))
|
||||
elif is_def_by.is_a("IfcRelDefinesByType"):
|
||||
type_psets = is_def_by.RelatingType.HasPropertySets
|
||||
if type_psets is None:
|
||||
continue
|
||||
for propset in type_psets:
|
||||
propsets.append(process_pset(propset))
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print("failed to load properties: {}".format(e))
|
||||
traceback.print_exc()
|
||||
|
||||
if len(propsets):
|
||||
self.prop_dict[str(p)] = propsets
|
||||
|
||||
print("property set dictionary has {} entries".format(len(self.prop_dict)))
|
||||
|
||||
class viewer(qtViewer3d):
|
||||
|
||||
instanceSelected = QtCore.pyqtSignal([object])
|
||||
|
||||
@staticmethod
|
||||
def ais_to_key(ais_handle):
|
||||
def yield_shapes():
|
||||
ais = ais_handle.GetObject()
|
||||
if hasattr(ais, 'Shape'):
|
||||
yield ais.Shape()
|
||||
return
|
||||
shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
|
||||
if not shp.IsNull():
|
||||
yield shp.Shape()
|
||||
return
|
||||
mult = ais_handle
|
||||
if mult.IsNull():
|
||||
shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
|
||||
if not shp.IsNull():
|
||||
yield shp
|
||||
else:
|
||||
li = mult.GetObject().ConnectedTo()
|
||||
for i in range(li.Length()):
|
||||
shp = OCC.AIS.Handle_AIS_Shape.DownCast(li.Value(i + 1))
|
||||
if not shp.IsNull():
|
||||
yield shp
|
||||
|
||||
return tuple(shp.HashCode(1 << 24) for shp in yield_shapes())
|
||||
|
||||
def __init__(self, widget):
|
||||
qtViewer3d.__init__(self, widget)
|
||||
self.ais_to_product = {}
|
||||
self.product_to_ais = {}
|
||||
self.counter = 0
|
||||
self.window = widget
|
||||
|
||||
def initialize(self):
|
||||
self.InitDriver()
|
||||
self._display.Select = self.HandleSelection
|
||||
|
||||
def load_file(self, f, setting=None):
|
||||
|
||||
if setting is None:
|
||||
setting = settings()
|
||||
setting.set(setting.USE_PYTHON_OPENCASCADE, True)
|
||||
|
||||
v = self._display
|
||||
|
||||
t = {0: time.time()}
|
||||
|
||||
def update(dt=None):
|
||||
t1 = time.time()
|
||||
if t1 - t[0] > (dt or -1):
|
||||
v.FitAll()
|
||||
v.Repaint()
|
||||
t[0] = t1
|
||||
|
||||
terminate = [False]
|
||||
self.window.window_closed.connect(lambda *args: operator.setitem(terminate, 0, True))
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
it = iterator(setting, f)
|
||||
if not it.initialize():
|
||||
return
|
||||
|
||||
old_progress = -1
|
||||
while True:
|
||||
if terminate[0]:
|
||||
break
|
||||
shape = it.get()
|
||||
product = f[shape.data.id]
|
||||
ais = display_shape(shape, viewer_handle=v)
|
||||
ais.GetObject().SetSelectionPriority(self.counter)
|
||||
self.ais_to_product[self.counter] = product
|
||||
self.product_to_ais[product] = ais
|
||||
self.counter += 1
|
||||
QtWidgets.QApplication.processEvents()
|
||||
if product.is_a() in {'IfcSpace', 'IfcOpeningElement'}:
|
||||
v.Context.Erase(ais, True)
|
||||
progress = it.progress() // 2
|
||||
if progress > old_progress:
|
||||
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
|
||||
old_progress = progress
|
||||
if not it.next():
|
||||
break
|
||||
update(0.2)
|
||||
|
||||
print("\rOpened file in %.2f seconds%s" % (time.time() - t0, " " * 25))
|
||||
|
||||
update()
|
||||
|
||||
def select(self, product):
|
||||
ais = self.product_to_ais.get(product)
|
||||
if ais is None:
|
||||
return
|
||||
v = self._display.Context
|
||||
v.ClearSelected(False)
|
||||
v.SetSelected(ais, True)
|
||||
|
||||
def toggle(self, product_or_products, fn):
|
||||
if not isinstance(product_or_products, Iterable):
|
||||
product_or_products = [product_or_products]
|
||||
aiss = list(filter(None, map(self.product_to_ais.get, product_or_products)))
|
||||
last = len(aiss) - 1
|
||||
for i, ais in enumerate(aiss):
|
||||
fn(ais, i == last)
|
||||
|
||||
def toggle_visibility(self, product_or_products, flag):
|
||||
v = self._display.Context
|
||||
if flag:
|
||||
def visibility(ais, last):
|
||||
v.Erase(ais, last)
|
||||
else:
|
||||
def visibility(ais, last):
|
||||
v.Display(ais, last)
|
||||
self.toggle(product_or_products, visibility)
|
||||
|
||||
def toggle_wireframe(self, product_or_products, flag):
|
||||
v = self._display.Context
|
||||
if flag:
|
||||
def wireframe(ais, last):
|
||||
if v.IsDisplayed(ais):
|
||||
v.SetDisplayMode(ais, 0, last)
|
||||
else:
|
||||
def wireframe(ais, last):
|
||||
if v.IsDisplayed(ais):
|
||||
v.SetDisplayMode(ais, 1, last)
|
||||
self.toggle(product_or_products, wireframe)
|
||||
|
||||
def HandleSelection(self, X, Y):
|
||||
v = self._display.Context
|
||||
v.Select()
|
||||
v.InitSelected()
|
||||
if v.MoreSelected():
|
||||
ais = v.SelectedInteractive()
|
||||
inst = self.ais_to_product[ais.GetObject().SelectionPriority()]
|
||||
self.instanceSelected.emit(inst)
|
||||
|
||||
class window(QtWidgets.QMainWindow):
|
||||
|
||||
TITLE = "IfcOpenShell IFC viewer"
|
||||
|
||||
window_closed = QtCore.pyqtSignal([])
|
||||
|
||||
def __init__(self):
|
||||
QtWidgets.QMainWindow.__init__(self)
|
||||
self.setWindowTitle(self.TITLE)
|
||||
self.menu = self.menuBar()
|
||||
self.menus = {}
|
||||
|
||||
def closeEvent(self, *args):
|
||||
self.window_closed.emit()
|
||||
|
||||
def add_menu_item(self, menu, label, callback, icon=None, shortcut=None):
|
||||
m = self.menus.get(menu)
|
||||
if m is None:
|
||||
m = self.menu.addMenu(menu)
|
||||
self.menus[menu] = m
|
||||
|
||||
if icon:
|
||||
a = QtWidgets.QAction(QtGui.QIcon(icon), label, self)
|
||||
else:
|
||||
a = QtWidgets.QAction(label, self)
|
||||
|
||||
if shortcut:
|
||||
a.setShortcut(shortcut)
|
||||
|
||||
a.triggered.connect(callback)
|
||||
m.addAction(a)
|
||||
|
||||
def makeSelectionHandler(self, component):
|
||||
def handler(inst):
|
||||
for c in self.components:
|
||||
if c != component:
|
||||
c.select(inst)
|
||||
|
||||
return handler
|
||||
|
||||
def __init__(self, settings=None):
|
||||
QtWidgets.QApplication.__init__(self, sys.argv)
|
||||
self.window = application.window()
|
||||
self.tree = application.decomposition_treeview()
|
||||
self.tree2 = application.type_treeview()
|
||||
self.propview = self.property_table()
|
||||
self.canvas = application.viewer(self.window)
|
||||
self.tabs = QtWidgets.QTabWidget()
|
||||
self.window.resize(800, 600)
|
||||
splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
|
||||
splitter.addWidget(self.tabs)
|
||||
self.tabs.addTab(self.tree, 'Decomposition')
|
||||
self.tabs.addTab(self.tree2, 'Types')
|
||||
self.tabs.addTab(self.propview, "Properties")
|
||||
splitter2 = QtWidgets.QSplitter(QtCore.Qt.Vertical)
|
||||
splitter2.addWidget(self.canvas)
|
||||
self.editor = code_edit(self.canvas, configuration().options('snippets'))
|
||||
splitter2.addWidget(self.editor)
|
||||
splitter.addWidget(splitter2)
|
||||
splitter.setSizes([200, 600])
|
||||
splitter2.setSizes([400, 200])
|
||||
self.window.setCentralWidget(splitter)
|
||||
self.canvas.initialize()
|
||||
self.components = [self.tree, self.tree2, self.canvas, self.propview, self.editor]
|
||||
self.files = {}
|
||||
|
||||
self.window.add_menu_item('File', '&Open', self.browse, shortcut='CTRL+O')
|
||||
self.window.add_menu_item('File', '&Close', self.clear, shortcut='CTRL+W')
|
||||
self.window.add_menu_item('File', '&Exit', self.window.close, shortcut='ALT+F4')
|
||||
|
||||
self.tree.instanceSelected.connect(self.makeSelectionHandler(self.tree))
|
||||
self.tree2.instanceSelected.connect(self.makeSelectionHandler(self.tree2))
|
||||
self.canvas.instanceSelected.connect(self.makeSelectionHandler(self.canvas))
|
||||
for t in [self.tree, self.tree2]:
|
||||
t.instanceVisibilityChanged.connect(functools.partial(self.change_visibility, t))
|
||||
t.instanceDisplayModeChanged.connect(functools.partial(self.change_displaymode, t))
|
||||
|
||||
self.settings = settings
|
||||
|
||||
def change_visibility(self, tree, inst, flag):
|
||||
insts = tree.get_children(inst)
|
||||
self.canvas.toggle_visibility(insts, flag)
|
||||
|
||||
def change_displaymode(self, tree, inst, flag):
|
||||
insts = tree.get_children(inst)
|
||||
self.canvas.toggle_wireframe(insts, flag)
|
||||
|
||||
def start(self):
|
||||
self.window.show()
|
||||
sys.exit(self.exec_())
|
||||
|
||||
def browse(self):
|
||||
filename = QtWidgets.QFileDialog.getOpenFileName(self.window, 'Open file', ".",
|
||||
"Industry Foundation Classes (*.ifc)")[0]
|
||||
self.load(filename)
|
||||
|
||||
def clear(self):
|
||||
self.canvas._display.Context.RemoveAll()
|
||||
self.tree.clear()
|
||||
self.files.clear()
|
||||
|
||||
def load(self, fn):
|
||||
if fn in self.files:
|
||||
return
|
||||
f = open_ifc_file(str(fn))
|
||||
self.files[fn] = f
|
||||
for c in self.components:
|
||||
c.load_file(f, setting=self.settings)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
application().start()
|
||||
@@ -0,0 +1,149 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from code import InteractiveConsole
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
try:
|
||||
from PyQt5 import QtWidgets
|
||||
except BaseException:
|
||||
QtWidgets = QtGui
|
||||
|
||||
try:
|
||||
from pyqode.core.panels import CheckerPanel
|
||||
from pyqode.core import api
|
||||
from pyqode.core import modes
|
||||
from pyqode.core import panels
|
||||
from pyqode.core.api import CodeEdit, ColorScheme
|
||||
from pyqode.python.modes import PyAutoIndentMode, PythonSH
|
||||
from pyqode.python.backend import server
|
||||
from pyqode.python import modes as pymodes, panels as pypanels, widgets
|
||||
from pyqode.python.widgets import PyInteractiveConsole
|
||||
|
||||
has_pyqode = True
|
||||
except BaseException:
|
||||
has_pyqode = False
|
||||
CodeEdit = QtWidgets.QPlainTextEdit
|
||||
|
||||
|
||||
class StdoutRedirector(object):
|
||||
"""A class for redirecting stdout to this Text widget."""
|
||||
|
||||
def __init__(self, widget):
|
||||
self.widget = widget
|
||||
self.isError = False
|
||||
|
||||
def write(self, myStr):
|
||||
self.widget.moveCursor(QtGui.QTextCursor.End)
|
||||
if self.isError:
|
||||
self.widget.setTextColor(QtCore.Qt.red)
|
||||
else:
|
||||
self.widget.setTextColor(QtCore.Qt.white)
|
||||
self.widget.insertPlainText(myStr)
|
||||
self.widget.moveCursor(QtGui.QTextCursor.End)
|
||||
|
||||
|
||||
class code_edit(QtWidgets.QWidget):
|
||||
class Console(InteractiveConsole):
|
||||
def __init__(*args):
|
||||
InteractiveConsole.__init__(*args)
|
||||
|
||||
def enter(self, source):
|
||||
self.runcode(source)
|
||||
|
||||
def runCode(self):
|
||||
sys.stdout = StdoutRedirector(self.output)
|
||||
sys.stderr = StdoutRedirector(self.output)
|
||||
sys.stderr.isError = True
|
||||
|
||||
if not self.model:
|
||||
print("please load a model first", file=sys.stderr)
|
||||
else:
|
||||
self.c.enter(str(self.editor.toPlainText()))
|
||||
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stderr = sys.__stderr__
|
||||
|
||||
def select(self, product):
|
||||
self.c = self.Console({'model': self.model, 'viewer': self.viewer, 'selection': product})
|
||||
|
||||
def __init__(self, viewer, snippets=None):
|
||||
self.model = None
|
||||
self.viewer = viewer
|
||||
QtWidgets.QWidget.__init__(self)
|
||||
self.layout = QtWidgets.QVBoxLayout(self)
|
||||
self.setLayout(self.layout)
|
||||
self.c = None
|
||||
self.tools = QtWidgets.QHBoxLayout(self)
|
||||
self.layout.addLayout(self.tools)
|
||||
self.runbutton = QtWidgets.QPushButton("Run")
|
||||
width = self.runbutton.fontMetrics().boundingRect("Run").width() + 20
|
||||
self.runbutton.setMaximumWidth(width)
|
||||
self.tools.addWidget(self.runbutton)
|
||||
self.runbutton.clicked.connect(self.runCode)
|
||||
|
||||
editor = CodeEdit()
|
||||
if has_pyqode:
|
||||
editor.backend.start(server.__file__)
|
||||
editor.panels.append(panels.FoldingPanel())
|
||||
editor.panels.append(panels.LineNumberPanel())
|
||||
editor.panels.append(panels.SearchAndReplacePanel(),
|
||||
panels.SearchAndReplacePanel.Position.BOTTOM)
|
||||
editor.panels.append(panels.EncodingPanel(), api.Panel.Position.TOP)
|
||||
editor.add_separator()
|
||||
editor.panels.append(pypanels.QuickDocPanel(), api.Panel.Position.BOTTOM)
|
||||
sh = editor.modes.append(PythonSH(editor.document()))
|
||||
editor.modes.append(modes.CaretLineHighlighterMode())
|
||||
editor.modes.append(modes.CodeCompletionMode())
|
||||
editor.modes.append(modes.ExtendedSelectionMode())
|
||||
editor.modes.append(modes.FileWatcherMode())
|
||||
editor.modes.append(modes.OccurrencesHighlighterMode())
|
||||
editor.modes.append(modes.RightMarginMode())
|
||||
editor.modes.append(modes.SmartBackSpaceMode())
|
||||
editor.modes.append(modes.SymbolMatcherMode())
|
||||
editor.modes.append(modes.ZoomMode())
|
||||
editor.modes.append(pymodes.CommentsMode())
|
||||
editor.modes.append(pymodes.CalltipsMode())
|
||||
auto = pymodes.PyAutoCompleteMode()
|
||||
auto.logger.setLevel(logging.CRITICAL)
|
||||
editor.modes.append(auto)
|
||||
editor.modes.append(pymodes.PyAutoIndentMode())
|
||||
editor.modes.append(pymodes.PyIndenterMode())
|
||||
editor.show()
|
||||
else:
|
||||
editor.setStyleSheet('font-size: 10pt; font-family: Consolas, Courier;')
|
||||
|
||||
self.editor = editor
|
||||
self.snippets = snippets
|
||||
if self.snippets:
|
||||
self.list = QtWidgets.QComboBox(self)
|
||||
self.replace_snippet(0)
|
||||
for snip_name in self.snippets.keys():
|
||||
self.list.addItem(snip_name)
|
||||
self.tools.addWidget(self.list)
|
||||
self.list.currentIndexChanged[int].connect(self.replace_snippet)
|
||||
|
||||
self.layout.addWidget(self.editor)
|
||||
self.output = QtWidgets.QTextEdit()
|
||||
self.output.setReadOnly(True)
|
||||
self.output.setStyleSheet('font-size: 10pt; font-family: Consolas, Courier; background-color: #444;')
|
||||
self.layout.addWidget(self.output)
|
||||
|
||||
def replace_snippet(self, number=None):
|
||||
snip = list(self.snippets.values())[number]
|
||||
if has_pyqode:
|
||||
self.editor.setPlainText(snip, "", "")
|
||||
else:
|
||||
self.editor.setPlainText(snip)
|
||||
|
||||
def load_file(self, f, **kwargs):
|
||||
output = []
|
||||
sys.stdout = StdoutRedirector(self.output)
|
||||
self.model = f
|
||||
self.c = self.Console({'model': self.model, 'selection': None, 'viewer': self.viewer})
|
||||
sys.stdout = sys.__stdout__
|
||||
@@ -0,0 +1,201 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from .. import ifcopenshell_wrapper
|
||||
from ..file import file
|
||||
from ..entity_instance import entity_instance
|
||||
|
||||
|
||||
def has_occ():
|
||||
try:
|
||||
import OCC.BRepTools
|
||||
except BaseException:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
has_occ = has_occ()
|
||||
|
||||
|
||||
def wrap_shape_creation(settings, shape):
|
||||
return shape
|
||||
|
||||
|
||||
if has_occ:
|
||||
from . import occ_utils as utils
|
||||
|
||||
def wrap_shape_creation(settings, shape): return utils.create_shape_from_serialization(shape) if getattr(settings,
|
||||
'use_python_opencascade',
|
||||
False) else shape
|
||||
|
||||
|
||||
# Subclass the settings module to provide an additional
|
||||
# setting to enable pythonOCC when available
|
||||
|
||||
|
||||
class settings(ifcopenshell_wrapper.settings):
|
||||
if has_occ:
|
||||
USE_PYTHON_OPENCASCADE = -1
|
||||
|
||||
def set(self, *args):
|
||||
setting, value = args
|
||||
if setting == settings.USE_PYTHON_OPENCASCADE:
|
||||
self.set(settings.USE_BREP_DATA, value)
|
||||
self.set(settings.USE_WORLD_COORDS, value)
|
||||
self.set(settings.DISABLE_TRIANGULATION, value)
|
||||
self.use_python_opencascade = value
|
||||
else:
|
||||
ifcopenshell_wrapper.settings.set(self, *args)
|
||||
|
||||
|
||||
# Assert templated precision to match Python's internal float type
|
||||
assert ifcopenshell_wrapper.iterator_double_precision.mantissa_size() == sys.float_info.mant_dig
|
||||
_iterator = ifcopenshell_wrapper.iterator_double_precision
|
||||
|
||||
# Make sure people are able to use python's platform agnostic paths
|
||||
class iterator(_iterator):
|
||||
def __init__(self, settings, file_or_filename):
|
||||
self.settings = settings
|
||||
if isinstance(file_or_filename, file):
|
||||
file_or_filename = file_or_filename.wrapped_data
|
||||
else:
|
||||
file_or_filename = os.path.abspath(file_or_filename)
|
||||
_iterator.__init__(self, settings, file_or_filename)
|
||||
|
||||
if has_occ:
|
||||
def get(self):
|
||||
return wrap_shape_creation(self.settings, _iterator.get(self))
|
||||
|
||||
def __iter__(self):
|
||||
if self.initialize():
|
||||
while True:
|
||||
yield self.get()
|
||||
if not self.next(): break
|
||||
|
||||
class tree(ifcopenshell_wrapper.tree):
|
||||
|
||||
def __init__(self, file=None, settings=None):
|
||||
args = [self]
|
||||
if file is not None:
|
||||
args.append(file.wrapped_data)
|
||||
if settings is not None:
|
||||
args.append(settings)
|
||||
ifcopenshell_wrapper.tree.__init__(*args)
|
||||
|
||||
def add_file(self, file, settings):
|
||||
ifcopenshell_wrapper.tree.add_file(self, file.wrapped_data, settings)
|
||||
|
||||
def select(self, value, **kwargs):
|
||||
def unwrap(value):
|
||||
if isinstance(value, entity_instance):
|
||||
return value.wrapped_data
|
||||
elif all(map(lambda v: hasattr(value, v), "XYZ")):
|
||||
return value.X(), value.Y(), value.Z()
|
||||
return value
|
||||
|
||||
args = [self, unwrap(value)]
|
||||
if isinstance(value, entity_instance):
|
||||
args.append(kwargs.get("completely_within", False))
|
||||
elif has_occ:
|
||||
import OCC.TopoDS
|
||||
if isinstance(value, OCC.TopoDS.TopoDS_Shape):
|
||||
args[1] = utils.serialize_shape(value)
|
||||
return [entity_instance(e) for e in ifcopenshell_wrapper.tree.select(*args)]
|
||||
|
||||
def select_box(self, value, **kwargs):
|
||||
def unwrap(value):
|
||||
if isinstance(value, entity_instance):
|
||||
return value.wrapped_data
|
||||
elif hasattr(value, "Get"):
|
||||
return value.Get()[:3], value.Get()[3:]
|
||||
return value
|
||||
|
||||
args = [self, unwrap(value)]
|
||||
if "extend" in kwargs or "completely_within" in kwargs:
|
||||
args.append(kwargs.get("completely_within", False))
|
||||
if "extend" in kwargs:
|
||||
args.append(kwargs.get("extend", -1.e-5))
|
||||
return [entity_instance(e) for e in ifcopenshell_wrapper.tree.select_box(*args)]
|
||||
|
||||
|
||||
def create_shape(settings, inst, repr=None):
|
||||
"""
|
||||
Return a geometric representation from STEP-based IFCREPRESENTATIONSHAPE
|
||||
or
|
||||
Return an OpenCASCADE BRep if settings.USE_PYTHON_OPENCASCADE == True
|
||||
|
||||
example:
|
||||
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set(settings.USE_PYTHON_OPENCASCADE, True)
|
||||
|
||||
ifc_file = ifcopenshell.open(file_path)
|
||||
products = ifc_file.by_type("IfcProduct")
|
||||
|
||||
for i, product in enumerate(products):
|
||||
if product.Representation is not None:
|
||||
try:
|
||||
shape = geom.create_shape(settings, inst=product).geometry
|
||||
shape_gpXYZ = shape.Location().Transformation().TranslationPart() # These are methods of the TopoDS_Shape class from pythonOCC
|
||||
print(shape_gpXYZ.X(), shape_gpXYZ.Y(), shape_gpXYZ.Z()) # These are methods of the gpXYZ class from pythonOCC
|
||||
"""
|
||||
return wrap_shape_creation(
|
||||
settings,
|
||||
ifcopenshell_wrapper.create_shape(
|
||||
settings,
|
||||
inst.wrapped_data,
|
||||
repr.wrapped_data if repr is not None else None
|
||||
))
|
||||
|
||||
|
||||
def iterate(settings, filename):
|
||||
it = iterator(settings, filename)
|
||||
if it.initialize():
|
||||
while True:
|
||||
yield it.get()
|
||||
if not it.next():
|
||||
break
|
||||
|
||||
|
||||
def make_shape_function(fn):
|
||||
def entity_instance_or_none(e):
|
||||
return None if e is None else entity_instance(e)
|
||||
|
||||
if has_occ:
|
||||
import OCC.TopoDS
|
||||
|
||||
def _(schema, string_or_shape, *args):
|
||||
if isinstance(string_or_shape, OCC.TopoDS.TopoDS_Shape):
|
||||
string_or_shape = utils.serialize_shape(string_or_shape)
|
||||
return entity_instance_or_none(fn(schema, string_or_shape, *args))
|
||||
else:
|
||||
def _(schema, string, *args):
|
||||
return entity_instance_or_none(fn(schema, string, *args))
|
||||
return _
|
||||
|
||||
|
||||
serialise = make_shape_function(ifcopenshell_wrapper.serialise)
|
||||
tesselate = make_shape_function(ifcopenshell_wrapper.tesselate)
|
||||
@@ -1,42 +1,188 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import random
|
||||
from collections import namedtuple
|
||||
import operator
|
||||
from collections import namedtuple, Iterable
|
||||
|
||||
import OCC.gp
|
||||
import OCC.V3d
|
||||
import OCC.Quantity
|
||||
import OCC.BRepTools
|
||||
import OCC.Display.SimpleGui
|
||||
|
||||
tuple = namedtuple('shape', ('data', 'geometry'))
|
||||
shape_tuple = namedtuple('shape_tuple', ('data', 'geometry', 'styles'))
|
||||
|
||||
handle, main_loop, add_menu, add_function_to_menu = None, None, None, None
|
||||
|
||||
DEFAULT_STYLES = {
|
||||
"DEFAULT": (.7, .7, .7),
|
||||
"IfcWall": (.8, .8, .8),
|
||||
"IfcSite": (.75, .8, .65),
|
||||
"IfcSlab": (.4, .4, .4),
|
||||
"IfcWallStandardCase": (.9, .9, .9),
|
||||
"IfcWall": (.9, .9, .9),
|
||||
"IfcWindow": (.75, .8, .75, .3),
|
||||
"IfcDoor": (.55, .3, .15),
|
||||
"IfcBeam": (.75, .7, .7),
|
||||
"IfcRailing": (.65, .6, .6),
|
||||
"IfcMember": (.65, .6, .6),
|
||||
"IfcPlate": (.8, .8, .8)
|
||||
}
|
||||
|
||||
|
||||
def initialize_display():
|
||||
import OCC.V3d
|
||||
import OCC.Display.SimpleGui
|
||||
|
||||
global handle, main_loop, add_menu, add_function_to_menu
|
||||
handle, main_loop, add_menu, add_function_to_menu = OCC.Display.SimpleGui.init_display()
|
||||
|
||||
def setup():
|
||||
viewer_handle = handle.GetViewer()
|
||||
viewer = viewer_handle.GetObject()
|
||||
while True:
|
||||
|
||||
def lights():
|
||||
viewer.InitActiveLights()
|
||||
try: active_light = viewer.ActiveLight()
|
||||
except: break
|
||||
viewer.DelLight(active_light)
|
||||
viewer.NextActiveLights()
|
||||
for dir in [(1,2,-3), (-2,-1,1)]:
|
||||
while True:
|
||||
try:
|
||||
active_light = viewer.ActiveLight()
|
||||
except BaseException:
|
||||
break
|
||||
yield active_light
|
||||
viewer.NextActiveLights()
|
||||
|
||||
lights = list(lights())
|
||||
for l in lights:
|
||||
viewer.DelLight(l)
|
||||
|
||||
for dir in [(3, 2, 1), (-1, -2, -3)]:
|
||||
light = OCC.V3d.V3d_DirectionalLight(viewer_handle)
|
||||
light.SetDirection(*dir)
|
||||
viewer.SetLightOn(light.GetHandle())
|
||||
|
||||
setup()
|
||||
return handle
|
||||
|
||||
|
||||
def display_shape(shape, clr=None):
|
||||
if not clr:
|
||||
r = lambda: random.random() * 0.3 + 0.7
|
||||
def yield_subshapes(shape):
|
||||
import OCC.TopoDS
|
||||
|
||||
it = OCC.TopoDS.TopoDS_Iterator(shape)
|
||||
while it.More():
|
||||
yield it.Value()
|
||||
it.Next()
|
||||
|
||||
|
||||
def display_shape(shape, clr=None, viewer_handle=None):
|
||||
import OCC.gp
|
||||
import OCC.AIS
|
||||
import OCC.Quantity
|
||||
|
||||
if viewer_handle is None:
|
||||
viewer_handle = handle
|
||||
|
||||
if isinstance(shape, shape_tuple):
|
||||
shape, representation = shape.geometry, shape
|
||||
else:
|
||||
representation = None
|
||||
|
||||
material = OCC.Graphic3d.Graphic3d_MaterialAspect(OCC.Graphic3d.Graphic3d_NOM_PLASTER)
|
||||
material.SetDiffuse(1)
|
||||
|
||||
if representation and not clr:
|
||||
if len(set(representation.styles)) == 1:
|
||||
clr = representation.styles[0]
|
||||
if min(clr) < 0. or max(clr) > 1.:
|
||||
clr = DEFAULT_STYLES.get(representation.data.type, DEFAULT_STYLES["DEFAULT"])
|
||||
|
||||
if clr:
|
||||
ais = OCC.AIS.AIS_Shape(shape)
|
||||
ais.SetMaterial(material)
|
||||
|
||||
if isinstance(clr, str):
|
||||
qclr = getattr(OCC.Quantity, "Quantity_NOC_%s" % clr.upper(),
|
||||
getattr(OCC.Quantity, "Quantity_NOC_%s1" % clr.upper(), None))
|
||||
if qclr is None:
|
||||
raise Exception("No color named '%s'" % clr.upper())
|
||||
elif isinstance(clr, Iterable):
|
||||
clr = tuple(clr)
|
||||
if len(clr) < 3 and len(clr) > 4:
|
||||
raise Exception("Need 3 or 4 colour components. Got '%r'." % clr)
|
||||
qclr = OCC.Quantity.Quantity_Color(clr[0], clr[1], clr[2], OCC.Quantity.Quantity_TOC_RGB)
|
||||
elif isinstance(clr, OCC.Quantity.Quantity_Color):
|
||||
qclr = clr
|
||||
else:
|
||||
raise Exception("Object of type %r cannot be used as a color." % type(clr))
|
||||
|
||||
ais.SetColor(qclr)
|
||||
if isinstance(clr, tuple) and len(clr) == 4 and clr[3] < 1.:
|
||||
ais.SetTransparency(1. - clr[3])
|
||||
|
||||
elif representation and hasattr(OCC.AIS, "AIS_MultipleConnectedShape"):
|
||||
default_style_applied = None
|
||||
|
||||
ais = OCC.AIS.AIS_MultipleConnectedShape(shape)
|
||||
|
||||
subshapes = list(yield_subshapes(shape))
|
||||
lens = len(representation.styles), len(subshapes)
|
||||
if lens[0] != lens[1]:
|
||||
import warnings
|
||||
warnings.warn("Unable to assign styles to subshapes. Encountered %d styles for %d shapes." % lens)
|
||||
else:
|
||||
for shp, stl in zip(subshapes, representation.styles):
|
||||
subshape = OCC.AIS.AIS_Shape(shp)
|
||||
if min(stl) < 0. or max(stl) > 1.:
|
||||
default_style_applied = stl = DEFAULT_STYLES.get(representation.data.type,
|
||||
DEFAULT_STYLES["DEFAULT"])
|
||||
subshape.SetColor(OCC.Quantity.Quantity_Color(stl[0], stl[1], stl[2], OCC.Quantity.Quantity_TOC_RGB))
|
||||
subshape.SetMaterial(material)
|
||||
if len(stl) == 4 and stl[3] < 1.:
|
||||
subshape.SetTransparency(1. - stl[3])
|
||||
ais.Connect(subshape.GetHandle())
|
||||
|
||||
# For some reason it is necessary to set transparency here again
|
||||
# in order for transparency to be rendered on the subshape.
|
||||
applied_styles = representation.styles
|
||||
if default_style_applied:
|
||||
if len(default_style_applied) == 3:
|
||||
default_style_applied += (1.,)
|
||||
applied_styles += (default_style_applied,)
|
||||
|
||||
if len(applied_styles):
|
||||
# The only way for this not to be true if is the entire shape is NULL
|
||||
min_transp = min(map(operator.itemgetter(3), applied_styles))
|
||||
if min_transp < 1.:
|
||||
ais.SetTransparency(1.)
|
||||
|
||||
else:
|
||||
ais = OCC.AIS.AIS_Shape(shape)
|
||||
ais.SetMaterial(material)
|
||||
|
||||
def r():
|
||||
return random.random() * 0.3 + 0.7
|
||||
|
||||
clr = OCC.Quantity.Quantity_Color(r(), r(), r(), OCC.Quantity.Quantity_TOC_RGB)
|
||||
return handle.DisplayShape(shape, color=clr, update=True)
|
||||
ais.SetColor(clr)
|
||||
|
||||
ais_handle = ais.GetHandle()
|
||||
viewer_handle.Context.Display(ais_handle, False)
|
||||
|
||||
return ais_handle
|
||||
|
||||
|
||||
def set_shape_transparency(ais, t):
|
||||
@@ -44,23 +190,52 @@ def set_shape_transparency(ais, t):
|
||||
|
||||
|
||||
def get_bounding_box_center(bbox):
|
||||
bbmin = [0.]*3; bbmax = [0.]*3
|
||||
import OCC.gp
|
||||
|
||||
bbmin = [0.] * 3
|
||||
bbmax = [0.] * 3
|
||||
bbmin[0], bbmin[1], bbmin[2], bbmax[0], bbmax[1], bbmax[2] = bbox.Get()
|
||||
return OCC.gp.gp_Pnt(*map(lambda xy: (xy[0]+xy[1])/2., zip(bbmin, bbmax)))
|
||||
return OCC.gp.gp_Pnt(*map(lambda xy: (xy[0] + xy[1]) / 2., zip(bbmin, bbmax)))
|
||||
|
||||
|
||||
def serialize_shape(shape):
|
||||
import OCC.BRepTools
|
||||
|
||||
shapes = OCC.BRepTools.BRepTools_ShapeSet()
|
||||
shapes.Add(shape)
|
||||
return shapes.WriteToString()
|
||||
|
||||
|
||||
def create_shape_from_serialization(brep_object):
|
||||
brep_data, occ_shape = None, None
|
||||
|
||||
try: brep_data = brep_object.geometry.brep_data
|
||||
except: pass
|
||||
if not brep_data: return tuple(brep_object, None)
|
||||
|
||||
import OCC.BRepTools
|
||||
|
||||
brep_data, occ_shape, styles = None, None, ()
|
||||
|
||||
is_product_shape = True
|
||||
try:
|
||||
brep_data = brep_object.geometry.brep_data
|
||||
styles = brep_object.geometry.surface_styles
|
||||
except BaseException:
|
||||
try:
|
||||
brep_data = brep_object.brep_data
|
||||
styles = brep_object.surface_styles
|
||||
is_product_shape = False
|
||||
except BaseException:
|
||||
pass
|
||||
|
||||
styles = tuple(styles[i:i + 4] for i in range(0, len(styles), 4))
|
||||
|
||||
if not brep_data:
|
||||
return shape_tuple(brep_object, None, styles)
|
||||
|
||||
try:
|
||||
ss = OCC.BRepTools.BRepTools_ShapeSet()
|
||||
ss.ReadFromString(brep_data)
|
||||
occ_shape = ss.Shape(ss.NbShapes())
|
||||
except: pass
|
||||
|
||||
return tuple(brep_object, occ_shape)
|
||||
except BaseException:
|
||||
pass
|
||||
|
||||
if is_product_shape:
|
||||
return shape_tuple(brep_object, occ_shape, styles)
|
||||
else:
|
||||
return occ_shape
|
||||
|
||||
@@ -17,27 +17,41 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import uuid
|
||||
import string
|
||||
|
||||
from functools import reduce
|
||||
|
||||
chars = string.digits + string.ascii_uppercase + string.ascii_lowercase + '_$'
|
||||
|
||||
|
||||
def compress(g):
|
||||
bs = [int(g[i:i+2], 16) for i in range(0, len(g), 2)]
|
||||
bs = [int(g[i:i + 2], 16) for i in range(0, len(g), 2)]
|
||||
|
||||
def b64(v, l=4):
|
||||
return ''.join([chars[(v // (64**i))%64] for i in range(l)][::-1])
|
||||
return ''.join([b64(bs[0], 2)] + [b64((bs[i] << 16) + (bs[i+1] << 8) + bs[i+2]) for i in range(1,16,3)])
|
||||
return ''.join([chars[(v // (64 ** i)) % 64] for i in range(l)][::-1])
|
||||
|
||||
return ''.join([b64(bs[0], 2)] + [b64((bs[i] << 16) + (bs[i + 1] << 8) + bs[i + 2]) for i in range(1, 16, 3)])
|
||||
|
||||
|
||||
def expand(g):
|
||||
def b64(v):
|
||||
return reduce(lambda a, b: a * 64 + b, map(lambda c: chars.index(c), v))
|
||||
|
||||
bs = [b64(g[0:2])]
|
||||
for i in range(5):
|
||||
d = b64(g[2+4*i:6+4*i])
|
||||
bs += [(d >> (8*(2-j)))%256 for j in range(3)]
|
||||
return ''.join(['%02x'%b for b in bs])
|
||||
d = b64(g[2 + 4 * i:6 + 4 * i])
|
||||
bs += [(d >> (8 * (2 - j))) % 256 for j in range(3)]
|
||||
return ''.join(['%02x' % b for b in bs])
|
||||
|
||||
|
||||
def split(g):
|
||||
return '{%s-%s-%s-%s-%s}'%(g[:8], g[8:12], g[12:16], g[16:20], g[20:])
|
||||
return '{%s-%s-%s-%s-%s}' % (g[:8], g[8:12], g[12:16], g[16:20], g[20:])
|
||||
|
||||
|
||||
def new():
|
||||
return compress(uuid.uuid4().hex)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user