Compare commits

...

863 Commits

Author SHA1 Message Date
Andrej730 73817acdff add a note on get_info_2() #4270 2024-02-01 17:19:35 +05:00
Andrej730 3d7e8d7c6c Fixed #4259
Result of DeepDiff contain ordered sets. Also added fallback for usual sets to lists just in case, should be safe.
2024-01-30 15:41:08 +05:00
Andrej730 a701840826 Fixed error adding a boolean
It occured if active object was IFC object and second selected object was just Blender object.
2024-01-30 14:40:07 +05:00
Andrej730 5de2ac9042 black format 2024-01-30 14:36:35 +05:00
Andrej730 573e2626ad Fix test Model.get_manual_booleans after we added pset to store them 2024-01-30 14:36:35 +05:00
Andrej730 9de59afd49 Fix #4267 and add tests
Crash was caused by unmark_manual_booleans accessing boolean element after they were deleted from IFC
2024-01-30 14:36:35 +05:00
Andrej730 74a9671075 Update ui.py 2024-01-30 14:36:35 +05:00
Andrej730 799658ff41 display active representation presentation layer in UI
example - https://i.imgur.com/mpnoqPH.png
2024-01-30 14:36:35 +05:00
Andrej730 bd64f42a54 remove_representation to consider representation item's layers too
and purge layers if they are out of items as they become invalid
2024-01-30 14:36:35 +05:00
Andrej730 8eab7f155e Small presentation layers UI fixes 2024-01-30 14:36:35 +05:00
Andrej730 5351966430 access layer assignments from inverse attribute instead of going through representation inverses 2024-01-30 14:36:35 +05:00
Andrej730 2663c079f4 test for removing representation items 2024-01-29 16:47:17 +05:00
Andrej730 6747bd9c8f UI to remove representation items
example - https://i.imgur.com/jJDpIQP.png
2024-01-29 16:47:16 +05:00
Andrej730 6ece295be4 tests for creating shape aspects and adding items 2024-01-29 15:52:40 +05:00
Andrej730 64a9f85f25 create new shape aspects from UI
example - https://i.imgur.com/BJJZWrC.png
2024-01-29 15:52:39 +05:00
Andrej730 d8fa853308 edit shape aspect attributes from UI
example - https://i.imgur.com/SzUEn6r.png
2024-01-29 15:52:39 +05:00
Andrej730 ce37c49624 Fix #4262 after 0da3270c7 2024-01-29 11:13:22 +05:00
Andrej730 0da3270c7f UI for changing representation item's shape aspect
Example - https://imgur.com/a/tN7hCYz
2024-01-26 17:32:46 +05:00
Andrej730 fda6fc6c48 geometry.remove_representation documentation 2024-01-26 17:20:39 +05:00
Andrej730 3865f01df9 operator to remove representation item from shape aspect 2024-01-26 17:20:39 +05:00
Andrej730 6bf61d7163 Simple UI to display repr item shape aspect
Example - https://i.imgur.com/YEAE9zU.png
2024-01-26 15:27:05 +05:00
Andrej730 b8ad73668f BBIM to print console errors in case IFC file is failed to load 2024-01-26 14:54:51 +05:00
Andrej730 b7a3dd4164 black format 2024-01-26 14:54:50 +05:00
Bruno Postle 566fd443db IfcGit avoid leaving stray .git/config.lock files 2024-01-25 23:30:00 +00:00
Andrej730 51b5a507cf shape builder docs 2024-01-25 16:46:38 +05:00
Andrej730 a44357dad5 shape builder polyline example and tests 2024-01-25 16:46:34 +05:00
Andrej730 8e792ebb50 UI for changing styles for representation items
Example - https://imgur.com/a/SQh6rR2
2024-01-25 15:17:44 +05:00
Andrej730 352321364c fix couple building docs errors / warnings 2024-01-24 16:38:53 +05:00
Andrej730 2ab32e41b2 shape builder docs fixes 2024-01-24 16:38:53 +05:00
Andrej730 3fbd9d7cdf IFC4 Landscape Library
Created IFC library with simple trees, shrubs and hedges - with both 2d and 3d representations. Example - https://i.imgur.com/pOjh1si.png
Now it's available along with the furniture library when creating new project - https://i.imgur.com/Ho0B5Gn.png
2024-01-24 16:38:52 +05:00
Dion Moult 7a7fde0a2a See #4247. Loading models now skips excessively voided objects for performance. 2024-01-24 10:39:31 +11:00
Ryan Schultz 7992bd9902 Give user additional feedback when trying to duplicate an IFCproject and Drawing. Also deselects the object to prevent inadvertently moving it. 2024-01-23 08:04:12 -06:00
Dion Moult 3182fe9c15 Fix bug where merging by type when loading broke if a type didn't have a name 2024-01-23 19:45:31 +11:00
Dion Moult e8858aeeb3 Fix bug where loading filtered IFC2X3 models didn't work. 2024-01-23 17:39:13 +11:00
Dion Moult ec79d61095 Fix #2719. Indicator whether or not IFC is dirty to help users know when to save. 2024-01-23 16:29:42 +11:00
Dion Moult 266236ee49 See #4241. Only use shapely to repolygonise if IfcOpenShell returns unclosed paths. Hollow cuts typically are closed paths. 2024-01-23 16:06:54 +11:00
Dion Moult 192e4e43a4 Fix #4239. Stop users from duplicating IfcProject. 2024-01-23 12:30:25 +11:00
Dion Moult b22c92e951 Fix regression where you couldn't unlink an object that already had a broken element link, and bug where you couldn't unlink a spatial element or similar with its own collection. 2024-01-23 12:27:09 +11:00
Dion Moult 7634e71434 See #4239. Ensure that all copy pasted objects are unlinked. Use duplicate if you want to copy. 2024-01-23 12:25:46 +11:00
Dion Moult dda803df2e See 0028fd3. Fix regression when duplicating objects without connections. 2024-01-23 09:05:40 +11:00
Andrej730 c3ded31a6a static ifcopenshell.geom.serializers and some typing for IDE code hints
code itself should work exactly the same way
2024-01-22 14:24:24 +05:00
Thomas Krijnen f2d19ab2c3 #4216 todo note 2024-01-22 09:38:05 +01:00
Dion Moult ab80400e16 See #4240. Guard against possible user creating invalid userdefined attribute values. 2024-01-21 21:56:45 +11:00
Dion Moult c88496c6a6 See #4240. Fix validation issue with perspective drawing pyramid booleans. Boolean clipping results can only be used on swept solids. 2024-01-21 19:13:40 +11:00
Dion Moult 0ee07fb8cc See #4240. Fix bug where 2D arbitrary profiles were invalid IFC (used 3D point lists not 2D) 2024-01-21 16:07:00 +11:00
Dirk Olbrich 36cf458498 docs: include doxygen-awesome as git submodule 2024-01-20 14:05:50 +01:00
Dirk Olbrich e7c25bf99f docs: add README with instructions 2024-01-20 14:05:50 +01:00
Dirk Olbrich 50a3c8c2f3 docs: modify doxygen config to new folder 2024-01-20 14:05:50 +01:00
Dirk Olbrich f18298d1fd git: clean up gitignore 2024-01-20 14:05:50 +01:00
Dirk Olbrich d4770bdee3 docs: move C++ API docs to subfolder 2024-01-20 14:05:50 +01:00
Dirk Olbrich 1fb107c361 docs: include doxygen-awesome theme 2024-01-20 14:05:50 +01:00
Dirk Olbrich 0fa1e2d585 docs: remove duplicate cmake for Sphinx setup 2024-01-20 14:05:50 +01:00
Dirk Olbrich dc13f4c5cc docs: remove geom setting docs and images
- these are duplicated in /src/ifcopenshell-python/docs/ifcopenshell/
2024-01-20 14:05:50 +01:00
Dirk Olbrich d197c3f49a docs: update doxygen file to 1.9.8 2024-01-20 14:05:50 +01:00
Dirk Olbrich c05200a5c6 docs: set LOOKUP_CACHE_SIZE 2024-01-20 14:05:50 +01:00
Dirk Olbrich 235bb198da docs: update Doxyfile to v1.9.4
- specify ./output/doxygen as main path for output
- use relative paths for subfolder output
2024-01-20 14:05:50 +01:00
Dion Moult 40f332d674 Fix #3947. Do slight 2mm offset to account for Z-fighting on 2D plan views and RCPs. 2024-01-20 21:53:34 +11:00
Dion Moult e8a272dc97 Fix #4213. Allow having separate windows to trigger drawing operators. 2024-01-20 15:06:47 +11:00
Dion Moult 0b308770a6 See #4216. Document using OpenCASCADE geometry serialisation to create geometry. 2024-01-20 14:35:52 +11:00
Dion Moult 96c8323a06 Fix #4221. Only load leaf rows with cost values. Createing a monetary measure with None results in a segfault on Windows. 2024-01-20 14:17:19 +11:00
Dion Moult 25573cd0e0 Fix #4236. Consolidate revert, reload IFC, and reload selected IFC operations.
Reload IFC incrementally (via diff) is moved to the debug panel since it is a dangerous advanced user command.
2024-01-20 13:15:59 +11:00
Dion Moult ff3c7786f6 Fix #4109. Write docs about geometry serialiser. 2024-01-19 23:18:38 +11:00
Dion Moult 5f4dfcf215 Fix #4231. Bug where you couldn't add a door to an element assembly. 2024-01-19 22:47:53 +11:00
Andrej730 9a89555a53 bbim_translations.py - remove operator context from operator tooltips
noticed editing translations from ui that operator tooltip doesn't appear in ui if tooltips has `msgctxt "Operator"`
2024-01-19 16:31:34 +05:00
Dion Moult fc69a2acbe Fix #4127. Bug where IfcTester couldn't save ODS report. 2024-01-19 22:25:03 +11:00
Andrej730 85a2a5ad12 fix build error 2024-01-19 15:11:59 +05:00
Andrej730 49c3d28a0b Merge branch 'localization' into v0.7.0 2024-01-19 15:02:01 +05:00
Andrej730 a8f20b2c6b drop bpy related translations.py<->.po stuff as we won't be using it 2024-01-19 15:00:41 +05:00
Andrej730 66fa1cedd9 run bbim_translations.py without bpy 2024-01-19 15:00:41 +05:00
Andrej730 eb971d3d73 save just a final dictionary to translations.py instead of tuples
We can do that since In our workflow we won't be converting translations.py to .po files, that way it will be much shorter as it's containing only translated strings and doesn't have strings sources.
2024-01-19 13:58:49 +05:00
Andrej730 a30a796c07 generate translations.py without bpy 2024-01-19 13:58:49 +05:00
Andrej730 9e46bacc12 gettext bug fix 2024-01-19 12:06:11 +05:00
Ioannis P. Christovasilis b33378e135 ifc2ca major update - todo: update readme file 2024-01-18 12:53:31 +01:00
Vukas Pajic d42e19f491 Fix #4226 2024-01-18 08:54:24 +01:00
Eduardo Schilling 2597827ab3 Roof slope as percentage property 2024-01-18 09:40:33 +11:00
Dion Moult 3f71efea6d Fix #4227. Add shapely as an optional dependency for IOS-Python 2024-01-18 09:22:35 +11:00
Andrej730 2d279b7a7f update blenderbim build to include translation data 2024-01-17 17:18:04 +05:00
Andrej730 e5fe039fd0 expose current blender locale in bbim translations ui 2024-01-17 17:18:04 +05:00
Andrej730 9e14829cc1 bbim messages parser to also parse gettext 2024-01-17 17:10:26 +05:00
Andrej730 e867602d9d keep order of strings in .pot as they were parsed and store source filepaths 2024-01-17 17:10:26 +05:00
Andrej730 aecc3d56b8 switch to our own string parser instead of blender's 2024-01-17 17:10:26 +05:00
Andrej730 e3f5d3d2b7 rename BlenderBIM translation script/addon 2024-01-17 17:10:26 +05:00
Thomas Krijnen 65f8b1a532 #4222 template kw 2024-01-17 11:10:06 +01:00
Thomas Krijnen 96b4df10ba #4222 typename keywords 2024-01-17 11:02:02 +01:00
Andrej730 98b56aea42 allow missing translations.py as not everyone will need translations for BBIM 2024-01-17 12:07:02 +05:00
Andrej730 ba6ba29da8 auto enable "Manage UI Translations" addon if it's not enabled 2024-01-16 17:34:24 +05:00
Andrej730 1112b102f7 add without-blender-way to generate translations module from po files
though it does require `bpy` module which is available only for python 3.10.
Actually, `bpy` module by itself is not necessary - we just need `bl_i18n_utils` that becomes available after `import `bpy`. So alternatively we can just download that module from Blender https://projects.blender.org/blender/blender/src/branch/main/scripts/modules/bl_i18n_utils
2024-01-16 17:06:43 +05:00
Andrej730 04b8172ea9 black format 2024-01-16 15:28:55 +05:00
Andrej730 f5f3edbc79 check if translation ui is loaded by current Blender session instead of current Blender file
as it's more reliable and thing could change after Blender restart
2024-01-16 15:27:43 +05:00
Andrej730 30029e3dc7 expose i18n path in translator UI
removed bim.open_po_directory operator as it's now available just from alt-clicking on the path browsing button
2024-01-16 15:24:03 +05:00
Andrej730 ed836f5b4a Update bbim_setup_translations.py 2024-01-16 15:18:05 +05:00
Andrej730 a88b708442 fix issues with empty paths accepted as valid paths 2024-01-16 15:15:11 +05:00
Andrej730 764c3bbb85 separate developer/translator ui 2024-01-16 15:08:55 +05:00
Andrej730 382d3f1f9f generate pot file too converting translations.py 2024-01-16 15:04:02 +05:00
Thomas Krijnen c92f607a15 #4222 sprinkle with template keywords 2024-01-16 09:56:50 +01:00
Thomas Krijnen b57b7080fd #4220 weakref to file 2024-01-16 09:44:04 +01:00
Thomas Krijnen 860ff4e513 #4220 Update file.py 2024-01-16 09:31:35 +01:00
Andrej730 3546f13593 change test addon name from localization_test 2024-01-16 11:42:34 +05:00
Dion Moult 663966e08d Fix #4089. Document support for Linux AArch64 on Conda. 2024-01-16 11:19:17 +11:00
Dion Moult f077ebdc81 Fix #4211. Minor documentation fix that clarifies upstream bug about whether qto can be assigned to types. 2024-01-16 10:56:35 +11:00
Dion Moult eb888fd116 Fix #4223. Basic lint error. 2024-01-16 10:50:43 +11:00
Dion Moult 40b6b3bf17 Fix #4224. Fix sequencing lint bugs. 2024-01-16 10:47:50 +11:00
Dion Moult 2ef2f923d0 Fix #4219. Update documentation for creating a new model. 2024-01-16 10:45:13 +11:00
Bruno Postle 75fab58831 IfcGit fixes suggested by ruff 2024-01-15 22:16:19 +00:00
Andrej730 ce26c6e19b BBIM - upgrade to IFC4X3 on loading projects
Added "Upgrate to IFC4X3" button on loading new projects to migrate them to IFC4x3 as Ifc4x3 got approved now will be used more widely.

https://i.imgur.com/mHSIV7T.png
2024-01-15 17:39:49 +05:00
Andrej730 8728fa38b9 Migrator - basic support for migrating attributes ifc4 -> ifc4x3
And added one of the IfcProperty renamed attribute as an example
2024-01-15 17:39:49 +05:00
Dion Moult 3037795199 Fix #4139. Bulk purge orphaned classes and move advanced operators to debug panel. 2024-01-15 23:16:42 +11:00
Andrej730 39ee9cd8b1 Migrator - display some error message for unhandled schemas
Noticed it was resulting in error below migrating to IFC4X3 in some cases as we don't have a mapping for IFC4X3 yet.
```
    if value is None and not attribute.optional():
UnboundLocalError: local variable 'value' referenced before assignment
```
2024-01-15 16:16:29 +05:00
Andrej730 b375bbf558 black format 2024-01-15 16:16:29 +05:00
Thomas Krijnen f2cae79dea #4220 Update entity_instance.py 2024-01-15 12:01:18 +01:00
Andrej730 aadc77f6b6 minor fix for bim.create_all_shapes printed messages 2024-01-15 14:44:40 +05:00
Andrej730 35223d968c semi-automatic setup for necessary directories 2024-01-15 14:43:23 +05:00
Andrej730 e106dc4502 register translations dict only if addon is already loaded 2024-01-15 13:39:27 +05:00
Andrej730 2995b73c2d open .po directory operator 2024-01-15 13:39:27 +05:00
Andrej730 770bc6ea61 Operator to disable BBIM and restart Blender
as it's needed to reload the translations

Update bbim_setup_translations.py

Update bbim_setup_translations.py
2024-01-15 13:38:34 +05:00
Andrej730 f5736a7144 convert setup_translations to blender addon for UI 2024-01-15 12:18:53 +05:00
Dion Moult b4120b1cab Fix #4173. Don't recreate boundaries of building elements that already exist.
Inline opening processing. Minor improvement to detecting attributes for int/ext and physical/virtual.
2024-01-15 15:28:52 +11:00
Dirk Olbrich f44ca67ab9 readme: fix listed ifc version, add link to IFC4x3 docs 2024-01-15 09:20:15 +11:00
Dion Moult 77eae1c8e8 Fix #4195. Forgot to add UI for contains selector. 2024-01-14 23:20:06 +11:00
Dion Moult 02d79f0687 See #4173. Prototype new approach to generating 1st level space boundaries. 2024-01-14 23:12:14 +11:00
mohamadalbaaj 83d364574a Fixing Dimension Mismatch in Matrix Multiplication 2024-01-14 15:08:08 +11:00
Dion Moult 688d2b7bd1 Minor test fix 2024-01-13 16:49:27 +11:00
Dion Moult bf35239979 Fix bug where UI didn't show applicable psets to specific predefined types 2024-01-13 16:49:02 +11:00
Dion Moult ca8e014647 Fix #4195. Fix regressions from f840da3 and add support for "contains string" comparisons. 2024-01-13 15:58:57 +11:00
Dion Moult b5f63ec4f3 Fix #4196. Settings are now saved when you save Spreadsheet export JSON files. Also a new setting to generate an SVG alongside the spreadsheet (intended to be used as a schedule placed on a sheet). 2024-01-13 15:03:51 +11:00
Dion Moult aec2141128 Minor fix 2024-01-13 00:00:58 +11:00
Dion Moult 778344c804 Fix #4197. URLs in SVG schedules are now clickable. 2024-01-12 23:44:45 +11:00
Dion Moult 3ede9b254f Fix #4199. Bug where external references on sheets weren't properly referenced leading to no names. 2024-01-12 19:48:32 +11:00
Dion Moult 8df40dc4a6 Fix #4203. Fix bug where removing nested cost items left orphaned relationships. 2024-01-12 18:14:49 +11:00
Dion Moult 75dd4f3132 Fix #4204. Add support for XLSX schedules on sheets. 2024-01-12 17:26:04 +11:00
Christoph Mellueh be11df3dc1 sort code alphabetically 2024-01-12 08:43:50 +11:00
Christoph Mellueh 09ac212aa9 improve core file for better zen 2024-01-12 08:43:50 +11:00
Christoph Mellueh e159151b44 update BsDD to match new API
+ move Functions from operator to core/tool
2024-01-11 12:00:44 +11:00
Dion Moult 27f6ac0575 Fix #4198. Minor regression in updating text literals. 2024-01-11 09:53:48 +11:00
c4rlosdias f840da3ffd Added more comparisons in search 2024-01-10 23:21:18 +11:00
sennhvi 034df852b2 Update geometry_processing.rst
Add an usage example of the parameter include  for the Geometry Iterator
2024-01-10 23:19:46 +11:00
Christoph Mellueh f242071ebb add pset view to groups 2024-01-10 23:14:33 +11:00
Sigma Dimensions (Yass) b6663e9189 fix counting elements when importing cost schedules ( and run black) 2024-01-10 09:30:03 +01:00
Dion Moult 39d143668c Fix #4186. Support different RL insertion modes when adding occurrences of a type. 2024-01-10 18:53:05 +11:00
Dion Moult 6ea1e378c5 Fix bug where updating type text literals didn't propagate and formatting rounding null values wasn't handled. 2024-01-10 14:42:14 +11:00
Dion Moult a33f30e8ce Fix #4189. Hidden or non-isolated objects now don't show annotations. 2024-01-10 12:29:56 +11:00
Christoph Mellueh e79fb2ff0b add typing to BsDD 2024-01-10 09:10:38 +11:00
Christoph Mellueh 054b4d0ee2 add deprecation warnings 2024-01-10 09:10:38 +11:00
Christoph Mellueh 43bebf4eee update new api to BsDD 2024-01-10 09:10:38 +11:00
Thomas Krijnen 532869a48a #4182 Properly initialize filename in stream_or_filename class 2024-01-09 13:41:38 +01:00
Andrej730 6569d0031f monkey patch blender's dump_addon_messages
The way blender gather messages to translate is:
1) disable the addon
2) parse all available strings
3) enable the addon
4) parse all strings available strings again and subtract the ones gathered at step 2.

But due Blender bug (https://projects.blender.org/blender/blender/issues/116579) not all addon parts unregistered at step 1, so some addon's strings left out and gathered at step 2 and then subtracted at step 4. At the end, we loose them and they will be missing from resulting translations files.

I've monkey patched dump_addon_messages so it now works a bit more safe:
0) It expects addon to be disabled and Blender restarted after
1) Gather all Blender strings
2) Enable addon
3) Gather all Blender strings again and subtract strings from step 1.
2024-01-09 16:54:58 +05:00
Andrej730 bfaa61e592 setup_translations - original dump_addon_messages
same as with dump_py_messages - this commit is needed to track monkey patch changes later on
2024-01-09 16:46:22 +05:00
Andrej730 1a09ce40e9 fix error converting translations to .po if .po files already exist 2024-01-09 16:00:21 +05:00
Dion Moult 6f1b40fc86 Fix #4162. Reduce minimum area requirement for auto space generation down to 0.1sqm. 2024-01-09 18:20:51 +11:00
Dion Moult 734eec7715 See #4162. Fix bug with generating space from cursor due to numerical inaccuracies and colinear lines for shapely. 2024-01-09 18:13:29 +11:00
Dion Moult bfabc0db0f Add support for groups in selection queries 2024-01-09 16:44:40 +11:00
Dion Moult e71aac84dc Fix #4175. Add new UI for managing IFC object and edit modes. 2024-01-09 12:57:31 +11:00
Andrej730 c156100be2 Fix breaking spatial containers UI when spatial container is deleted
E.g. if you had some container selected in `active_container_id` and then it got deleted UI would break and won't allow to reload the spatial manger until you reload .ifc completely
2024-01-08 15:53:10 +05:00
Andrej 48c2b43a58 Merge pull request #4171 from c-mellueh/fix-SurfaceStyle-loader-bug
Fix Surface Style Loader Bug
2024-01-08 12:31:14 +05:00
Dion Moult 2f8cfb5a95 Fix #4161. Deprecate unmaintained barebones LCA module. 2024-01-08 16:59:31 +11:00
Eduardo Schilling 1c4cc34c1b Add degrees format display 2024-01-08 16:54:58 +11:00
Eduardo Schilling b81e03d9c2 Add stair calculated parameter Pitch 2024-01-08 16:54:58 +11:00
Dion Moult eb96858460 Fix #4167. Bug where pset template module didn't allow creating qto template types. 2024-01-08 16:52:59 +11:00
Dion Moult 5c7e70e987 Minor fix to loading nested ports 2024-01-08 16:03:57 +11:00
Dion Moult 9093c9d419 Fix #4176. Bug where tabbed interface didn't work on new or temporary screens. 2024-01-08 16:03:34 +11:00
Dion Moult 02a5b8d997 Fix #4178. Bug when removing the wrong classification reference. 2024-01-08 13:48:35 +11:00
Sigma Dimensions (Yass) f1b5f7d558 add conversion based unit symbols 2024-01-05 18:45:54 +01:00
Thomas Krijnen 742a9ecd81 IfcParseExamples requires C++17 now 2024-01-05 09:04:34 +01:00
Thomas Krijnen 77a497cdf7 Generalize shortened file.schema attribute 2024-01-04 15:05:40 +01:00
CyrilWaechter 00576ef574 IfcRelSpaceBoundary: Add error handling and better error message for user 2024-01-04 10:22:51 +01:00
Sigma Dimensions (Yass) c26caaa58d fix resource cost calculation 2024-01-04 09:33:55 +01:00
Sigma Dimensions (Yass) b260bd3877 Record formula and resource name for cost values when calculating resource cost 2024-01-04 09:32:31 +01:00
Sigma Dimensions (Yass) cd6246c382 fix cost value calculation when using parent cost 2024-01-04 09:30:27 +01:00
Sigma Dimensions (Yass) a96d6dacc7 Display cost value names, and add import operator for cost schedule panel 2024-01-04 09:29:50 +01:00
CyrilWaechter 64c711a02a IfcRelSpaceBoundary: Create almost all boundaries for a selected space
* Refactor boundary creation to allow usage in a loop.
* Loop through all building element in building storey instead of stopping to the first one
* Enforce checking to prevent creation of invalid boundary geometries
2024-01-03 16:37:10 +01:00
Christoph Mellueh 68a2480a66 turn list into tuple 2024-01-03 13:42:14 +01:00
CyrilWaechter d5e2fd5d3c Fix some url and add missing ones 2024-01-03 01:11:05 +01:00
CyrilWaechter bb445663f8 Bump IOS and use more update friendly url 2024-01-03 00:22:50 +01:00
CyrilWaechter 1f7db75572 Add python 3.11 to blenderbim build matrix 2024-01-02 20:59:04 +01:00
CyrilWaechter f478ec8d6b black boundary operator.py 2024-01-02 18:49:50 +01:00
CyrilWaechter cf3ba334b7 IfcRelSpaceBoundary: make sure parent boundary is whole 2024-01-02 18:49:05 +01:00
CyrilWaechter c36af110c4 IfcRelSpaceBoundary: Improve inner boundary generation workflow and boundary names
# Inner boundaries
Some software or workflow generates many opening for the same element (eg. window) so it is not relevant to create inner boundaries for opening with no filling.

# Boundary name
Apply convention for 1st and 2nd Level boundaries
2024-01-02 17:52:23 +01:00
Kristoffer Andersen 91eac7085b Update meta.yaml
pin swig version for conda
2024-01-02 15:46:48 +01:00
Thomas Krijnen 239d1d6fd2 C++ get_psets() with extensive preprocessor trickery 2023-12-30 16:14:10 +01:00
Thomas Krijnen 831709d514 Update src/ifcopenshell-python/docs/ifcopenshell-python/geometry_processing.rst 2023-12-30 10:03:10 +01:00
wangsenhui 5925476ed9 add geometry processing with multiple representations example 2023-12-30 10:03:10 +01:00
wangsenhui 3edb3c8df3 add geometry processing with multiple representations example 2023-12-30 10:03:10 +01:00
wangsenhui 72badd8427 add geometry processing with multiple representations example 2023-12-30 10:03:10 +01:00
Andrej730 ff251b7a6a monkey patch dump_py_messages to ignore blenderbim dependencies 2023-12-29 17:36:12 +05:00
Andrej730 dbce57ffc5 setup_translations - original dump_py_messages
as we're going to monkey patch it and this commit is needed to keep the history of changes
2023-12-29 17:36:12 +05:00
Andrej730 8ff9bcef32 update translations in current blender session 2023-12-29 17:13:43 +05:00
Andrej730 82b2006686 setup_translations.py - use just 1 directory to store .po files
and use temp directory to store .po files for ui_translate.export/import
2023-12-29 17:13:43 +05:00
Andrej730 ca4181c714 fixed typo 2023-12-29 16:58:31 +05:00
Andrej730 3928dd7c9c BBIM - register translation strings #889 2023-12-29 15:33:38 +05:00
Andrej730 925964ee2a BBIM script to reload/export/import translation strings #889 2023-12-29 15:33:30 +05:00
Thomas Krijnen 7201df8d22 p21 binary should be uppercase 2023-12-26 14:28:45 +01:00
Andrej730 7b65108a76 ifctester - added some typing for IDE type hints 2023-12-26 16:18:08 +05:00
Andrej730 0fbe4d80c7 Clean up IfcIndexedColourMap removing representation #4138
Because we wasn't removing colour map, remove_representation was producing orphaned IfcPolygonalFaceSet that were referred by colour map.
2023-12-26 11:33:20 +05:00
Ryan Schultz 54c689d615 Applying multiple opening objects in bulk
Merry Christmas.
2023-12-25 10:33:49 -06:00
Andrej730 ab828b1a8b ifcpixeltexture tests to reflect actual order of data 2023-12-25 16:22:08 +05:00
Andrej730 8ddd349f8b Fixed issue with flipped ifcblobtexture loaded to blender 2023-12-25 16:21:05 +05:00
Andrej730 3221219f4a save ifcblobtexture and ifcpixeltexture to .blend file 2023-12-25 14:36:58 +05:00
Andrej730 36387f348e Fixed issue changing type of object creating opening in an aggregate
More: https://community.osarch.org/discussion/1888/error-after-trying-to-change-a-window-type-whose-opening-is-applied-to-an-aggregate#latest

A bit related to #3973 in case if it will be resolved
2023-12-25 11:49:06 +05:00
Andrej730 c39c6d81e3 Note on not allowing aggregates with representation #3973 2023-12-25 11:47:58 +05:00
Andrej730 e8042de1ed expose assign/unassign aggregation hotkey to bim tool ui 2023-12-25 11:03:10 +05:00
Andrej730 78fd999c53 Fix a few uses of assigning/unassigning agregation after 165262933 2023-12-25 10:38:51 +05:00
dushyant basson 91d1cb79c2 Using transformation-matrix data; Turned off world-coords; Re-using geometry of repeating IDs 2023-12-24 11:57:14 +01:00
dushyant basson 832618b84a initial camera-orientation; multiple materials in a single element; default material used from IfcGeom; improved triangle node data generation for OSG 2023-12-24 11:57:14 +01:00
dushyant basson e4ce53d548 update 2023-12-24 11:57:14 +01:00
dushyant basson 7b92b5c7e2 IFC file successfully parsed and loaded in Qt OpenGL widget 2023-12-24 11:57:14 +01:00
dushyant basson c8c08439b2 added header-guard 2023-12-24 11:57:14 +01:00
dushyant basson 3476ee8fd5 debug messages 2023-12-24 11:57:14 +01:00
dushyant basson d2f331c813 update 2023-12-24 11:57:14 +01:00
dushyant basson 9e9b294f44 Implemented: Application icons; OpenSceneGraph to handle OpenGL with Qt; devicePixelRatio() for handing render on highDPI displays; Sample 3D with handler; MouseHandler not yet working as expected (WIP) 2023-12-24 11:57:14 +01:00
Dushyant Basson f824ee8ca4 updated .ico file 2023-12-24 11:57:14 +01:00
dushyant basson 919f673108 add application file icon for macos 2023-12-24 11:57:14 +01:00
Dushyant Basson b034b40b09 application file-icon and window-icon set on ms-windows 2023-12-24 11:57:14 +01:00
dushyant basson 34f038530f Removed .clangd file from tracking and added it to .gitignore 2023-12-24 11:57:14 +01:00
dushyant basson 1c70990b06 Removed .clangd file from tracking and added it to .gitignore 2023-12-24 11:57:14 +01:00
dushyant basson 07eecad433 adding qt resources 2023-12-24 11:57:14 +01:00
Sigma Dimensions (Yass) ef87f0fe74 New Clash management panel to load IFCClash collision results 2023-12-23 09:14:08 +01:00
Sigma Dimensions (Yass) 23c2d73e8e fix smart clash group selection 2023-12-23 09:11:20 +01:00
Andrej730 0b47fb5987 Fix typo in 92cf0d9 2023-12-22 21:53:31 +05:00
Andrej730 8a1dee532b Support loading styles with IfcPixelTexture 2023-12-22 19:22:14 +05:00
Andrej730 f0c6c4ca59 Allow copying node graphs for external shaders on Blender 4.1+ #3876 2023-12-22 16:40:48 +05:00
Andrej730 92cf0d9265 remove_representation not to leave brokens refs with batch_remove #4138 2023-12-22 16:04:52 +05:00
Andrej730 7c438b6b9b Purge IfcWindow/DoorStyle/IfcTypeProduct #4137 2023-12-21 14:26:43 +05:00
Sigma Dimensions (Yass) 46454c5c94 consider unit basis for calculating resource costs #4122 2023-12-20 14:19:16 +01:00
Andrej730 73aeafb063 Fix issue renaming objects first time project was loaded after 962b8fa
E.g. if you load a project and try to rename some element to "test" it will renamed to "test" instead of "IfcWindow/test" e.g.

Since we relid on `obj.name` handler to set `.is_renaming` back to `False`, it didn't set it back to False when project was just loaded and renamed object was not yet linked to ifc element and name handler is not yet setup.

Another option was to check whether object is linked before changing `is_renaming` but just setting it to False should be more more explicit.
2023-12-20 16:51:02 +05:00
Kristoffer Andersen e06297940f Update ci.yml
Hopefully this fixes ccache
2023-12-20 12:28:24 +01:00
Andrej730 1652629332 prefix bim.assign/unassign_object to avoid operator override #4099
Co-Authored-By: Bruno Perdigão <57102715+brunoperdigao@users.noreply.github.com>
2023-12-20 13:51:26 +05:00
Andrej730 3d8de40407 Fix for 308457300
Co-Authored-By: Bruno Postle <bruno@postle.net>
2023-12-20 11:00:24 +05:00
ay-ex 308457300e fix cmake regex for used blender python version 2023-12-19 15:46:32 +05:00
Andrej730 6ef96841ac Temp disable setting paint_active_slot from external materials #4129 2023-12-19 14:38:23 +05:00
Andrej730 289b2d1e9d Less console errors if failed to find external styles library
Now:
```
Error: Error loading external style - cannot find file: 'D:\Dropbox\GitHub\OD_Textures\Closed (Encrypted)\Materials.blend'
```

Before:
```
File "\blenderbim\bim\module\style\prop.py", line 250, in update_shading_style
Error: Error loading external style - cannot find file: 'D:\Dropbox\GitHub\OD_Textures\Closed (Encrypted)\Materials.blend'
Traceback (most recent call last):
  File "\blenderbim\bim\module\style\prop.py", line 255, in update_shading_style
    bpy.ops.bim.activate_external_style(material_name=blender_material.name)
  File "L:\Games\SteamLibrary\steamapps\common\Blender\4.0\scripts\modules\bpy\ops.py", line 109, in __call__
    ret = _op_call(self.idname_py(), kw)
RuntimeError: Error: Error loading external style - cannot find file: 'D:\Dropbox\GitHub\OD_Textures\Closed (Encrypted)\Materials.blend'
```
2023-12-19 14:38:23 +05:00
Kristoffer Andersen 96db699ad2 Merge pull request #4125 from Krande/fix/convert-units
Proposal for updating IfcPatch ConvertLengthUnit.py for compatibility with boost>=1.82
2023-12-19 06:43:01 +01:00
Andrej730 6b7eec0db6 Fix #4124 2023-12-18 12:28:19 +05:00
Sigma Dimensions (Yass) 80f35d0bda Fix CSV workschedule import - handle date-related attributes more gracefully 2023-12-17 20:25:23 +01:00
Sigma Dimensions (Yass) df390a655d fix displaying derived task durations 2023-12-17 20:20:52 +01:00
krande 593fca7c3d remove ci-py-only.yml as ci.yml already does this 2023-12-17 18:42:15 +01:00
krande 9335c8a0c8 add test and update ci 2023-12-17 18:09:28 +01:00
krande eccc21277d update ci 2023-12-17 15:42:38 +01:00
krande 2ce7e16537 add fix for ci tests 2023-12-17 15:33:35 +01:00
Thomas Krijnen 49835ee303 nix build-all: don't strip non-release wrapper builds 2023-12-17 13:18:34 +01:00
krande f5500da0af remove ifc2x3 conditional in conversion utility 2023-12-16 14:18:13 +01:00
krande c9552fac29 update name of function to make its purpose more clear 2023-12-16 14:01:36 +01:00
krande b11b3b7fa8 update unit_assignment 2023-12-16 13:47:18 +01:00
krande 8aecee5836 initial proposal for updating units conversion 2023-12-16 13:37:38 +01:00
Bruno Postle 2f3b3011ec BlenderBIM IFC Git set push.autoSetupRemote
When pushing to a remote repository set tracking for the current branch
so that a locally created repository behaves the same (on the
command-line) as a cloned repository
2023-12-15 23:26:52 +00:00
Andrej730 491c9203b0 test for loading ifc with blob textures 2023-12-15 18:19:59 +05:00
Andrej730 7f2b996d23 test for loading ifc style to blender material 2023-12-15 18:19:59 +05:00
Andrej730 d2ea6f6656 BBIM to support loading IfcBlobTexture 2023-12-15 18:19:59 +05:00
Andrej730 25128e8aa8 support to add all surface style types creating new IfcSurfaceStyle
Previously it was working only for shading styles, for other styles it worked but then produced errors as IfcSurfaceStyle.Styles end up being None.
2023-12-15 18:19:59 +05:00
Dion Moult 30fa917e69 Patch recipes can now be performed in-place and are sorted in the UI. 2023-12-15 23:09:34 +11:00
Dion Moult 40e494996d Add support for manual classifications and references 2023-12-15 23:09:34 +11:00
Andrej730 cfdc54064e disable rel paths for adding ref images and textures with unsaved .ifc 2023-12-14 18:53:54 +05:00
Andrej730 6daead6b61 Fixed issues using relative paths for external styles
- removed redundant notion about saving .blend file
- relative paths were saved incorrectly
- fix issue using "bim.browse_external_style" if IfcSurfaceStyle already has external style and it's either .blend file or material in it is missing (it was failing opening file browser)
2023-12-14 18:47:55 +05:00
Andrej730 241d52f0ad small error message fix
as it appears as one of the messages during .ifc load, that way it will be more clear that it's related to external styles
2023-12-14 18:43:17 +05:00
Andrej730 68dd93da1d Fix issue BrowseExternalStyle not selecting current external style in file manager 2023-12-14 17:43:12 +05:00
Andrej730 82703670f0 Pull all shading related material attributes from external styles #4053 2023-12-14 17:42:17 +05:00
Dion Moult cb8462a0d0 New SetWorldCoordinateSystem patch. Autodesk software is starting to pay attention to this attribute which I find really confusing. 2023-12-14 17:02:00 +11:00
Dion Moult 000245c26c Nesting collections only generate for element nesting, not port nesting 2023-12-14 16:50:56 +11:00
Andrej730 d97ee8eed4 Support editing IfcSurfaceStyleLighting in UI 2023-12-13 16:57:23 +05:00
Andrej730 f8af28f12a style.edit_surface_style to support editing IfcSurfaceStyleLighting
It was failing because api method wasn't supporting IfcColourRgb attributes edit in general but only for IfcSurfaceStyleShading.SurfaceColour
2023-12-13 16:53:58 +05:00
Andrej730 f6fab30d0a Support editing IfcSurfaceStyleRefraction in UI 2023-12-13 15:16:52 +05:00
Andrej730 f1a4ed702b Hide IfcStyledItem from bim.print_unused_elements_stats
as IfcStyledItem can be not referred by any other element and it doesn't mean it's not used in the project
2023-12-13 14:29:10 +05:00
Andrej730 c4080626df style.add_surface_texture to work without blender material provided 2023-12-13 14:07:48 +05:00
Bruno Postle a8078e38d2 Fix Clipping divide error (reported in #4057) 2023-12-12 22:15:59 +00:00
Andrej730 c52fe8abf9 data.py rename for consistency 2023-12-12 16:14:19 +05:00
Andrej730 b310b5aaba Remove old external styles UI from material in favor of general styles UI
Adding external styles from other styles now also moved to general styles UI - https://i.imgur.com/uEyjKVY.png
2023-12-12 16:12:55 +05:00
Andrej730 7246e75085 Fix after 2520a9305 2023-12-12 15:32:40 +05:00
Andrej730 48c0378bff Fixed #4105 2023-12-12 14:48:04 +05:00
Andrej 91c90e7b86 Merge pull request #4095 from c4rlosdias/v0.7.0 2023-12-12 14:09:14 +05:00
Thomas Krijnen 72abdb0569 Update build-all.py - py vers 2023-12-11 16:00:36 +01:00
Andrej730 7947ba4aaf Override some more blender scene panels #3842 2023-12-11 16:35:21 +05:00
Andrej730 2520a93055 Fix issues unregistering overridden panels
Previously overridden scene panels were removed but original panels were not restored.
Also added condition check for Blender version to generate list of panels to override, so we won't miss any errors using `try - except`.
2023-12-11 16:35:21 +05:00
Andrej730 fa480d99a2 Procedural override for default blender panels, hide keying panels #3842
also fixed the issue with default scene panels that were parented to other panels - because we didn't change `bl_parent_id` the panel structure for them was broken.
2023-12-11 16:35:21 +05:00
Bruno Postle 72c057e7a0 BlenderBIM user docs update after 6452872 2023-12-10 22:13:05 +00:00
Carlos Dias 61cfb361fa Update __init__.py
Fix bug
2023-12-08 11:09:28 -03:00
Andrej730 3786cfa666 Fixed issues with linked elements from linked blend files #4081
In #4081 reported the case when during redo (changing param in operator's popup) `Ifc.rebuild_element_maps` was relinking elements without discarding possible linked blender libraries. It end up accidentally linking some library's objects to the current Ifc file leading to errors.

Also fixed possible similar issue in couple other places.
2023-12-08 18:38:09 +05:00
Andrej730 cabc06821f test for tool.Blender.copy_node_graph #3876 2023-12-08 16:58:11 +05:00
Dion Moult f9fef4f5f6 Fix #4085. Classification reference URIs now have a button you can jump to that link. 2023-12-08 16:35:46 +11:00
Dion Moult 7c89d072e2 Fix #4086. Add support for non predefined bSDD pset and qto values. 2023-12-08 15:07:46 +11:00
Dion Moult dbb9e8c907 Fix #4092. Minor bug with bad detection of text literals when switching geometry. 2023-12-08 14:03:46 +11:00
Dion Moult 2df5b4c70e Fix #4090. Bug where profile set generator didn't accommodate optional axes. 2023-12-08 12:17:48 +11:00
Andrej730 a5aa608240 Fix reference images import after styles ui change 2023-12-07 18:09:17 +05:00
Andrej730 f7454366cc Representation Items UI - replace icon for active style
Now it's more consistent because we use the same icon is Styles UI
2023-12-07 18:09:17 +05:00
Andrej730 f773480917 style.edit_surface_style - fix crash setting attribute to None
Occured on setting IfcColourOrFactor attribute to None (e.g. DiffuseColour).
2023-12-07 18:09:17 +05:00
Andrej730 89f9cd0403 Styles UI - moved UI from shader graph N-panel to Styles UI #3912
Moved all shading style and textures parameters from shader-graph N-panel to general Styles UI. Shader graph now also update in real time on any prop changes in Styles UI.

Now there is practically no need to switch to shader graph to edit styles shaders - all parameters are available from the Styles UI. That also allows you to edit styles and see the results in viewport even if the edited style is not the one that's currently active.

small demo - https://imgur.com/a/i2suoZw
2023-12-07 18:09:16 +05:00
Martin15135215 b21159c6b3 add cff for ifcsverchok 2023-12-07 13:42:32 +11:00
Martin15135215 227f556669 add cff for serializers 2023-12-07 13:42:32 +11:00
Martin15135215 42bd69929c add cff for qtviewer 2023-12-07 13:42:32 +11:00
Martin15135215 a3532b24b3 add cff for ifcwrap 2023-12-07 13:42:32 +11:00
Martin15135215 5486c4c8e9 add cff for ifctester 2023-12-07 13:42:32 +11:00
Martin15135215 0259d4c0cd add cff for ifcpatch 2023-12-07 13:42:32 +11:00
Martin15135215 66c4c61dc2 add cff for ifcparse 2023-12-07 13:42:32 +11:00
Martin15135215 0f32ffe232 add cff for ifcopenshell-python 2023-12-07 13:42:32 +11:00
Martin15135215 72630de77a add cff for ifcmax 2023-12-07 13:42:32 +11:00
Martin15135215 9395bed72b add cff for ifcjni 2023-12-07 13:42:32 +11:00
Martin15135215 507a5cab83 add cff for ifcgeom_schema_agnostic 2023-12-07 13:42:32 +11:00
Martin15135215 a46a60996d add cff for ifcgeom 2023-12-07 13:42:32 +11:00
Martin15135215 3106168889 add cff for ifcfm 2023-12-07 13:42:32 +11:00
Martin15135215 7e0c0c5c83 add cff for ifcdiff 2023-12-07 13:42:32 +11:00
Martin15135215 19205c8774 add cff for ifccsv 2023-12-07 13:42:32 +11:00
Martin15135215 62b5f1d728 add cff for ifcconvert 2023-12-07 13:42:32 +11:00
Martin15135215 299df62758 add cff for ifcclash 2023-12-07 13:42:32 +11:00
Martin15135215 e58bfde500 Add cff for ifccityjson 2023-12-07 13:42:32 +11:00
Martin15135215 b60306cdbd add cff for ifcblender 2023-12-07 13:42:32 +11:00
Bruno Perdigão 61e0549e65 add_aggregate now add the empty using the 3d cursor location 2023-12-07 13:40:16 +11:00
Ryan Schultz 52ae759218 Added classification to selector 2023-12-07 13:39:42 +11:00
c4rlosdias 9b41614eff Update Load bSDD domains 2023-12-07 13:38:25 +11:00
Dirk Olbrich 58e01751c1 bbim-docs: add interface property editor section
- add stubs for each sub-tab
2023-12-07 13:19:46 +11:00
Dirk Olbrich 624134d033 bbim-docs: use figure with caption instead of plain image 2023-12-07 13:19:46 +11:00
Dirk Olbrich 22f83b68e4 bbim-docs: update workspace doc for sidebar panels 2023-12-07 13:19:46 +11:00
Dion Moult 1b35ea122e Implement support for managing nest hosts and components. 2023-12-07 13:19:29 +11:00
Ryan Schultz f1deefbcb3 Merge pull request #3969 from brunoperdigao/refactor-duplicate-aggregate
Refactor duplicate aggregate
2023-12-06 14:39:43 -06:00
Dion Moult d6c020b5ee Fix #4076. Fix bug where drawing activation priorities didn't match drawing generation priorities, and switching to a text literal representation failed. 2023-12-06 23:04:21 +11:00
Dion Moult ff4eddf38a Fix #4078. Bug in IfcTester that didn't allow certain facets to be used as applicabilities. Also canonicalise facet ordering for convenience. 2023-12-06 15:06:11 +11:00
Dion Moult 2b34dc4ce7 Fix bug in TessellateElements patch recipe where sometimes the patch would run forever. 2023-12-06 14:16:18 +11:00
Dion Moult 530260ebe7 Run black on cityjson2ifc 2023-12-05 09:54:38 +11:00
Dion Moult 594268c860 Fix two minor bugs in cityjson2ifc 2023-12-05 09:54:38 +11:00
Andrej730 e5fa8a01b4 fixed couple styles ui bugs
1) it was failing adding a new IfcSurfaceStyle if surface_style_class != Shading/Render as surface_style was not defined

2) It was never creating render material as IfcSurfaceStyleRendering class is a child of IfcSurfaceStyleShading and if statement never got to the is_a("IfcSurfaceStyleRendering") check
2023-12-04 17:38:22 +05:00
Andrej730 ad934cd9a6 Use paths relative to .ifc instead of .blend choosing texture paths
Texture path file dialog is also filtering image files now.

Removed subtype from `FILE_PATH` from all related props since `layout.prop()` for those props starts file dialog that cannot return path relative to .ifc. It can return path relative to .blend - though it can be processed in props update to convert to relative to .ifc, this doesn't allow setting relative paths if .blend is not saved. Therefore, I've created a separate operator.

add
2023-12-04 16:42:31 +05:00
Andrej730 92fe325816 Store reference images by relative paths #3447 2023-12-04 16:42:31 +05:00
Andrej730 818bb9c823 Fix normals for generic parametric stairs #4020
Also made concrete stair normals defined more explicitly.
2023-12-04 16:42:30 +05:00
Andrej d71fad988d Merge pull request #4071 from maxfb87/fix_clone_opening 2023-12-04 16:39:34 +05:00
Dion Moult ff0d6c810f Fix #4072. IDS reports now include filename. 2023-12-04 17:26:57 +11:00
Dion Moult 8b72929d22 Fix #4073. Objects with no applicable context for the drawing view are now hidden. 2023-12-04 12:47:07 +11:00
Bruno Postle 6452872e83 BlenderBIM IFC Git allow branch creation from HEAD
Previously you could only create branches by checking out an older
revision, making changes and committing it. This was an annoyance as
typically you are making changes to the HEAD of a branch, then you
realise this should have been a branch - now you can create the branch
on commit (#3096)
2023-12-03 16:15:09 +00:00
Ryan Schultz 88d2c61453 Merge pull request #3906 from IfcOpenShell/si_unit_w_cad_tools
allow SI with CAD tools.
2023-12-03 09:59:14 -06:00
Bruno Postle f777be6403 BlenderBIM IFC Git fix typo in function name 2023-12-02 23:59:07 +00:00
Massimo Fabbro 9aad249586 fix #3834. Now clone opening produces valid IFC files 2023-12-02 17:38:28 +01:00
Thomas Krijnen 7168f8eeff #2796 don't fail on null guid for rooted element deletion 2023-12-01 15:49:31 +01:00
Andrej730 da306c6141 Reference images attached to the drawings #3447
You can also save them as annotation types.
Example - https://imgur.com/a/6trT7SZ
2023-12-01 17:05:02 +05:00
Andrej730 e53c0b74b1 bim.update_representation to save non-body representations styles #3447 2023-12-01 16:53:50 +05:00
Andrej730 cb2f58ba0f Fixed issue importing drawing's IfcAnnotations with styles #3447 2023-12-01 16:53:50 +05:00
Andrej730 c0c7727f36 fix poll errors 2023-12-01 16:53:50 +05:00
Andrej730 60526e62b4 Revert "Minor fix - remove redundant code"
This reverts commit 7828508179.

Turned out when I was assuming `bim.add_style` is assigning the style but it wasn't, it was `bim.update_representation` on the file save. So basically during the session style wasn't assigned, therefore I added back explicit style assignment. 😬
2023-12-01 16:53:50 +05:00
Andrej730 496e58418a fixed typo 2023-12-01 16:53:50 +05:00
Thomas Krijnen b976ad3880 occ_utils.py - #1037 2023-12-01 12:42:09 +01:00
MicheleBenedetti 31a763fe12 mistype-fix 2023-12-01 10:34:11 +11:00
Andrej730 93ef2d0349 Fixed issues applying arrays
because pset wasn't removed BBIM was recognizing those elements as parts of an array resulting in issues during deletion and duplication. This issue is a regression after ec4f0e5, the root problem was that `keep_objs` wasn't working with `sync_children`.

Since `keep_objs` was used only for applying array layers I've replaced it with `array_layers_to_apply` that works for both `sync_children` = True and False.

https://community.osarch.org/discussion/1831/duplicating-failed-for-array-items-after-apply-array
2023-11-30 16:24:39 +05:00
Andrej730 7828508179 Minor fix - remove redundant code
style assignment was already done by `bim.add_style`
2023-11-30 10:41:57 +05:00
Dion Moult 7aa6be8e8a FixRevitTINs patch now also flips normals for surface TINs instead of solid TINs.
Minor fixes to use view_layer.object.active etc instead of context.active_object when running via Blender UI (it seems when you run the patch recipe from the Blender UI at least in later versions, context does not have an "active_object" property.
2023-11-30 14:58:32 +11:00
Andrej730 0679956add bim.add_reference_image #3447
Added operator to load image references as planes that will be stored in IFC.

Button location - https://i.imgur.com/L87BPyX.png
Example - https://imgur.com/a/JJXyU6C
2023-11-29 17:23:27 +05:00
Andrej730 b86f924543 move all operators added to "add mesh" menu to common method in ui.py 2023-11-29 15:12:33 +05:00
Dion Moult 962b8fac67 Fix #4049. New basic "regenerate occurrence name" operator. 2023-11-29 17:36:59 +11:00
Dion Moult fdcb705551 Fix #4054. You can now select objects based on diff results. 2023-11-29 16:27:20 +11:00
Dion Moult b80ca3c167 See #4054. Diffing now allows partial loading of changed elements to make it easier to visualise without loading and linking two models. 2023-11-29 15:57:59 +11:00
Dion Moult e8bd272189 Fix #4057. Data objects for the API are now in util.data instead of mixed into the shape builder utility and only depends on numpy. 2023-11-29 14:36:01 +11:00
Bruno Postle 25bd94e84a minor documentation typo fix 2023-11-28 23:28:38 +00:00
Bruno Postle 5face7170f Fix python 3.12 SyntaxWarning (#4045)
Regular expressions now need to be double-escaped:
https://docs.python.org/3/whatsnew/3.12.html#other-language-changes
2023-11-28 22:51:58 +00:00
Dion Moult 434a11a502 Fix #4057. Move clipping info dataclass to util.shape_builder 2023-11-29 09:28:24 +11:00
krande eb91f5179b suggested change of ifcwrap pythoninterpreter function to no longer rely on distutil (which is deprecated in python 3.12). 2023-11-28 15:03:31 +01:00
Andrej730 c6643da4ba created uv map to have constistent name with Blender uvs
Previously it was named "Float2"
2023-11-28 16:01:10 +05:00
Andrej730 18c93a13ec moved load_texture_map to tool.Loader, added a test 2023-11-28 15:53:40 +05:00
Andrej730 7cb582de5d bim.save_uv_to_style - experimental operator to save current uv to ifc
it's very limited and covering very little cases now. It works only for IfcPolygonalFaceSets representations that consists of triangles.

Short example - https://imgur.com/a/1AxunSN
2023-11-28 15:53:40 +05:00
Andrej730 a5bb458d3d fixed issue importing uv failing for some IfcPolygonalFaceSets
It was failing with IfcIndexedTriangleTextureMap + IfcPolygonalFaceSet
2023-11-28 15:34:21 +05:00
Andrej730 c7f6a5e621 fixed issue importing uv on non meters projects 2023-11-28 12:17:31 +05:00
Andrej730 141e0240d4 fixed issue settings style blender props if there are not texture style 2023-11-28 12:17:30 +05:00
Andrej730 15cd2b6075 fixed issue with importing ifc objects with uv after 03a6ee912 2023-11-28 12:17:30 +05:00
Dion Moult fab8b5b702 Fix #3059. Implement IfcTester prohibited string templates (taking into account double negatives) 2023-11-28 17:20:20 +11:00
c4rlosdias 844f4c4944 Update IfcTester and Tester module of Blenderbim 2023-11-28 16:48:19 +11:00
Dion Moult 03809b3d5e Fix #3996. Reassigning occurrences or types now also reassigns the correlating occurrence or type. 2023-11-28 16:44:31 +11:00
Dion Moult 3e268be5c7 Fix #4052. Bug where invalid plane was generated due to missing X axis. 2023-11-28 11:52:56 +11:00
Dion Moult 6e932ec2fb Fix #3974. Bug where orphaned histories would be left in API remove operations. 2023-11-28 10:46:03 +11:00
Kristoffer Andersen 58414777be Update installation.rst
add more information about conda package installation
2023-11-27 10:25:11 +01:00
Dion Moult 14f1acadb7 See #3974. WIP review to ensure history removal in API. 2023-11-27 18:31:55 +11:00
Andrej730 f215670381 Small styles UI tweaks
- fixed a typo in bim.select_by_style
- added note to clarify what Shade/Render/Texture/Lighting/etc buttons do and moved style selection block at the beggining (maybe it's just me but when edit buttons are above selection ui it seemed like they affect all the styles somehow, not just the currently active one), so it will be more intuitive

Before:
https://i.imgur.com/jRSTLGI.png

After:
https://i.imgur.com/8ih4qSX.png
2023-11-27 12:29:28 +05:00
Andrej730 11df5065e4 bim.validate_ifc_file to detect if there where no validation errors 2023-11-27 11:18:38 +05:00
Dion Moult ed47b6b227 Fix #4044. Bug where object in camera view algorithm was wrong. Simplied to simple AABB test. 2023-11-25 16:02:51 +11:00
Andrej730 6216ee9a98 Fixed issue duplicating IfcRelSpaceBoundary #4043 2023-11-24 20:37:23 +05:00
Andrej730 848d6b294e Fixed console errors with BIM Tool when boundary object is selected 2023-11-24 20:24:25 +05:00
Andrej730 795a372ac9 test creating surface style without IFC entities 2023-11-24 16:49:02 +05:00
Andrej730 03a6ee9121 BBIM Shader Graph Settings - setting uv mode for the textures
Now you can set UV mode that will be used to sample textures (previously it was always using UV data on geometry or breaking if it was otherwise). Basically now you can use autogenerated UV for the objects without UV.

https://i.imgur.com/WtYdpmU.png

Removed BIMMaterialProperties.ifc_coordinate_id as it was only used during the ifc_import and maintained by the `Loader.create_surface_style_with_textures` which is also used to update live shader graph that not always have specific IFC id for the UV.
2023-11-24 15:52:31 +05:00
Andrej730 5299a9d8a2 Fixed issue updating texture style for non-faceset representations 2023-11-24 15:24:56 +05:00
Kristoffer Andersen a5d5d72064 Update meta.yaml
add python version to conda build string
2023-11-24 09:29:34 +01:00
Kristoffer Andersen b6f2a76385 Update ci-ifcopenshell-conda-daily.yml
add anaconda-client to the mamba env dependencies
2023-11-24 08:30:05 +01:00
Dion Moult ea6c8fe2f8 Fix #4027. Fix regression where S-D or A-D hotkeys didn't follow vanilla Blender behaviour from 81a1bd9 2023-11-24 15:09:29 +11:00
Dion Moult c7268b6f42 Fix #4037. IfcTester reports now also include an element type column. 2023-11-24 14:44:28 +11:00
Dion Moult 5937ed4b63 Fix #4034. Bug where abstract pset template applicabilities didn't apply to occurrences as well as types. 2023-11-24 14:02:27 +11:00
Bruno Postle 8f650c56e5 Revert 1d972a6 as no datetime.UTC on CI server 2023-11-23 21:59:23 +00:00
Bruno Postle 1d972a6a6f fix python 3.12 utcnow() deprecation warning
Warning is:

/usr/lib64/python3.12/site-packages/ifcopenshell/api/project/create_file.py:61:
DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version.
Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
2023-11-23 21:16:24 +00:00
Bruno Postle 70a1d7d345 python api documentation fix 2023-11-23 21:15:24 +00:00
Kristoffer Andersen 519d59effe Update ci-ifcopenshell-conda-daily.yml 2023-11-23 20:38:11 +01:00
Kristoffer Andersen 7f5f67b131 Update meta.yaml 2023-11-23 20:35:28 +01:00
Kristoffer Andersen 8c64d9ddcc Update ci-ifcopenshell-conda-daily.yml
Update repo activation
2023-11-23 17:23:01 +01:00
Kristoffer Andersen 397f333db0 Merge pull request #4041 from Krande/v0.7.0-conda/update
V0.7.0 conda/daily-builds-update
2023-11-23 17:17:16 +01:00
krande b01bd8afb3 only modify windows in CMakeLists.txt 2023-11-23 16:05:00 +01:00
krande 1dd8624825 need to use a push trigger on fork (dispatch is not allowed on PR from forks it seems). 2023-11-23 15:55:23 +01:00
krande bc0c2e641b make modifications to support conda hdf5 1.14 in CMakeLists.txt 2023-11-23 15:51:41 +01:00
krande f5f68ea150 add a workflow dispatch trigger (lets you click a button in the github actions workflow panel to start a new build) 2023-11-23 15:39:24 +01:00
krande 76ce117b46 test one more time on my fork before merging 2023-11-23 15:37:41 +01:00
krande 52cad9d11c pin windows hdf5 to 1.12
windows hdf5 1.14 results in ninja: error: 'libhdf5_cpp.lib', needed by 'IfcConvert.exe', missing and no known rule to make it
2023-11-23 15:30:41 +01:00
krande 58af81e256 drop "all" variant for now. Will include if people request it. 2023-11-23 15:17:59 +01:00
krande fc2da4ee8f add conda-forge as a channel 2023-11-23 15:11:46 +01:00
krande c04fa12051 add mamba env name 2023-11-23 15:09:24 +01:00
krande 623d2b5be1 add matrix variant to workflow name and do not use conda env yml file 2023-11-23 15:06:56 +01:00
krande 46319634fb run it once on fork 2023-11-23 15:05:17 +01:00
krande 91d2e5ccd1 add novtk/all variants to daily builds 2023-11-23 14:58:34 +01:00
Bruno Perdigão d23e32c64a added report messages 2023-11-23 10:57:17 -03:00
Kristoffer Andersen 764efa1fed Update ci-ifcopenshell-conda-daily.yml
add missing multiline flag for condarc setup
2023-11-23 14:33:10 +01:00
Kristoffer Andersen b051adcc6c Update ci-ifcopenshell-conda-daily.yml
change from deprecated mamba provisioner and move to python 3.11 and 3.12
2023-11-23 14:31:53 +01:00
Bruno Perdigão b815719477 added the option to refresh different groups of linked aggregate 2023-11-23 10:27:54 -03:00
Gorgious56 0612d2b615 You can now select the same ifc classes and match predefined types with SHIFT + Clicking the "Select Ifc Class" button 2023-11-23 09:52:37 +01:00
Andrej730 0da210b732 edit_object_placement optimization for objects with subchildren #4035
1) We were iterating over same subchildren 2 or more times.
2) There is no need to change subchildren position at all since their parent position is already adjusted.

Explained here in detail - https://github.com/IfcOpenShell/IfcOpenShell/issues/4035#issuecomment-1822824352
2023-11-23 13:43:39 +05:00
Dion Moult 9429e478fe Fix #3691. Add toggle for power users to disable the BIM toolbar if an IFC isn't loaded. 2023-11-23 14:59:26 +11:00
Dion Moult 2f6c50d9c2 New style manager supports basic editing of externally defined surface styles 2023-11-23 13:17:33 +11:00
Dion Moult 640341715c Minor IfcPatch doc fix where examples had a missing argument 2023-11-23 12:07:29 +11:00
Dion Moult 42878e325e Minor fix to "select multiple IFC class" implementation 2023-11-23 11:18:04 +11:00
Dion Moult ac5cf95f9e IfcFM panel now autodetects available engines with names and descriptions 2023-11-23 11:00:10 +11:00
Ryan Schultz c9189055c7 Select all objects from multiple selected classes 2023-11-22 10:47:04 -06:00
Andrej730 6a08993f5e fill userdefined type field during reassigning IFC class #4034
to avoid confusion
2023-11-22 15:01:36 +05:00
Andrej730 df2a50b335 store path to bcf in Blender file to reaccess it on Blender restart
Previously it was throwing errors if load .bcf and then restart Blender, since it was just trying to reaccess file in BcfStore.bcfxml which is gone after Blender restart. Now we store filepath to bcf in Blender properties to reload it after Blender restart.

Removed BCFProperties.is_loaded as it won't be possible to rely on it after Blender restart - after restart it will still indicate that file is loaded and it won't be possible to change it from .poll and .draw if file is gone.
2023-11-22 11:55:07 +05:00
Dion Moult c7543ff48d New graphical element filtering UI for drawing filters that lets you also use saved searches. 2023-11-22 15:33:30 +11:00
Dion Moult 1f75fa09ae If there is a Blender offset, show the non-offset placement in the placement panel 2023-11-22 11:32:14 +11:00
Dion Moult 94ce8e2c9c Fix bug when loading IFC with unsupported reflectance method (even though we don't fully support them yet) 2023-11-22 11:00:47 +11:00
Dion Moult 85e94d2cfc Move georeferencing calculator panel until scene georeferencing panel.
Slowly all the N sidebar panels should be moved away.
2023-11-22 11:00:47 +11:00
Andrej730 c2b332da48 BCF Viewpoint - clear selection before hiding IfcSpaces #4031 2023-11-21 22:12:26 +05:00
Andrej730 6ee4edd0a0 Fixed issue reassigning class to type class with userdefined type #4018
When PredefinedType is not found in the related enum reassign_class is considering it USERDEFINED and trying to set .ObjectType. The problem was it was doing for type classes also, when it should have set .ElementType instead.

Why it crashed BlenderBIM - in IfcClassData.data["has_entity"] we store currently active IFC entity which is recreated during `ifcopenshell.util.schema.reassign_class` making old entity invalid. Since `root.reassign_class` was failing in the process, related BBIM operator was failing too, IfcClassData wasn't updated and removed entity was accessed from UI leading to crash.
2023-11-21 12:35:35 +05:00
Dion Moult 0d757027e3 Fix critical georeferencing autodetection regression due to refactor of new context filters. 2023-11-21 15:10:01 +11:00
Dion Moult 9ffe56e64d Improve geometry guessing to also check placements of random sample of elements (not just site and building), not just geometry 2023-11-21 14:21:09 +11:00
Dion Moult 37a9a1b5d9 New IfcPatch recipe to tessellate elements to account for bugs in other vendors. 2023-11-21 14:21:09 +11:00
Dion Moult c30c9d50c9 Fix missing LGPL license blocks in IfcPatch 2023-11-21 14:21:09 +11:00
Bruno Perdigão 8e64b55290 bugfix in recreate_aggregate 2023-11-20 22:05:41 -03:00
Bruno Perdigão b45001a95a fix conflicts 2023-11-20 18:40:17 -03:00
Bruno Perdigão fd65009f5a Refresh Linked Aggregate now handles multiple selection 2023-11-20 18:34:46 -03:00
Bruno Perdigão 52036e9bd4 merged the branch 'improvements-on-override-duplicat' 2023-11-20 16:38:10 -03:00
Bruno Perdigão 5399767898 Merge branch 'improvements-on-override-duplicate' into refactor-duplicate-aggregate 2023-11-20 16:24:16 -03:00
Bruno Perdigão f96d477d2b Groups are only added to the parent. Parts now have a pset with index 2023-11-20 16:23:34 -03:00
Andrej730 d5f3991d06 Fixed more overlooked context overrides... #3876 2023-11-20 15:13:54 +05:00
Andrej730 2f2e81f585 Fixed #4026 related to #3876 2023-11-20 14:47:06 +05:00
Andrej730 0b7442b288 Move code using ui index from data to ui #4028
As UI indices changes doesn't trigger data.py updates and information on screen is not synced with the active item anymore.
2023-11-20 12:24:06 +05:00
Dion Moult 229c7285c2 Add support for loading nested elements and consider nesting for indirect spatial containment. 2023-11-20 16:57:38 +11:00
Dion Moult 4fb99d2eed Don't unnecessarily merge materials which can be very computationally consuming on file loads (e.g. from software like Solidworks) which will be made redundant now that a new materials/style management system is WIP. 2023-11-20 16:57:38 +11:00
Dion Moult 123557939f New ConvertNestToAggregate patch recipe 2023-11-20 16:57:38 +11:00
Bruno Postle 3c396d3180 IfcGit.load_project() can be used to refresh scene
If no file path is given, clear blender objects and regenerate
the scene from the current ifc project in IfcStore
2023-11-19 10:49:58 +00:00
Massimo Fabbro 5d39603308 fix #4011. More precise IfcRoof qto calculator 2023-11-17 16:39:29 +01:00
Massimo Fabbro b792673f88 Minor fix 2023-11-17 16:14:08 +01:00
Massimo Fabbro cf65612a96 Covering Tool: fixed bug if the project is defined in units different from SI units 2023-11-17 16:14:08 +01:00
Andrej730 50bbe849ff minor fix to support union typing before python 3.10 #3774 2023-11-17 18:57:51 +05:00
Andrej730 dc438b2560 ClippingInfo util class to pass and apply plane clippings #3774
Co-Authored-By: Carlos Villagrasa <carvillasil@gmail.com>
2023-11-17 16:52:59 +05:00
Andrej730 6750dd927c minor fixes
- error in settings poll message for bim.assign_selected_as_product
- test that drawing.assign_product won't create new assignments for the same product
2023-11-17 12:30:34 +05:00
Andrej730 9fb1986cad minor fix - clean up after debug 2023-11-16 19:26:12 +05:00
Andrej730 60f8d30fc1 Tests for connecting mep elements and regenerating them
Also:
- fixed bug with bim.mep_connect_elements not considering actual blender blender object's position
- moved syncing ifc position with blender object position to tools (sync_object_ifc_position)
- fixed a bug in adding a bend that occured if either any of the start/end points of the start/end segments matched - in that case one of the segments end up not connected to the bend
2023-11-16 19:15:56 +05:00
Ryan Schultz 67be2e8ce8 Refresh different types of aggregates at one time 2023-11-15 21:40:15 -06:00
Andrej730 2557580500 Fixed error importing .ifc that has element aggregated by ifcproject
In case if some element (not another aggregate) was aggregated by IfcProject directly, importing IFC was resulting in error below since the project's collection was never added to `self.collections`.

Traceback:
```
  File "\scripts\addons\blenderbim\bim\module\project\operator.py", line 732, in execute
    ifc_importer.execute()
  File "\scripts\addons\blenderbim\bim\import_ifc.py", line 292, in execute
    self.place_objects_in_collections()
  File "\scripts\addons\blenderbim\bim\import_ifc.py", line 1668, in place_objects_in_collections
    self.place_object_in_collection(self.file.by_id(ifc_definition_id), obj)
  File "\scripts\addons\blenderbim\bim\import_ifc.py", line 1672, in place_object_in_collection
    self.place_object_in_decomposition_collection(element, obj)
  File "\scripts\addons\blenderbim\bim\import_ifc.py", line 1689, in place_object_in_decomposition_collection
    return self.collections[aggregate.GlobalId].objects.link(obj)
KeyError: '2bKVb8E7L6e89EQYJUk8BM'
```
2023-11-15 18:33:20 +05:00
Andrej730 c0d2ac6ff9 Assigning product from selected objects #4015 2023-11-15 17:12:08 +05:00
Dion Moult 52c168051e Revert "You can now override custom category element functions in IfcFM"
This reverts commit 8a63275db0.
2023-11-15 17:19:10 +11:00
Dion Moult e072da8d65 Minor alignment of Basic FM preset to IFC property naming 2023-11-15 16:47:42 +11:00
Dion Moult 8a63275db0 You can now override custom category element functions in IfcFM 2023-11-15 16:35:46 +11:00
Dion Moult 69be3a005c Minor bug fix to COBie 2.4 space descriptions 2023-11-15 15:59:24 +11:00
Dion Moult ad9ad3f060 Purge data recipe now also purges shape aspect names and layers. 2023-11-15 14:22:21 +11:00
Bruno Perdigão f0e5304b8e fix conflicts merging with v0.7.0 2023-11-14 11:58:35 -03:00
Andrej730 c6454803ee fixed issue adding bend between segments located at the same point
also added some tests
2023-11-14 17:18:57 +05:00
Andrej730 e8aa8c44e5 Fixed issue with UI for types withotu PredefinedType after 1621449
Noticed the issue adding IfcFurnitureType in IFC2x3

```
Traceback (most recent call last):
  File "\Blender\4.0\scripts\addons\blenderbim\bim\module\model\workspace.py", line 71, in draw_settings
    BimToolUI.draw(context, layout, ifc_element_type="all")
  File "\Blender\4.0\scripts\addons\blenderbim\bim\module\model\workspace.py", line 230, in draw
    AuthoringData.load(ifc_element_type)
  File "\Blender\4.0\scripts\addons\blenderbim\bim\module\model\data.py", line 56, in load
    cls.data["predefined_type"] = cls.predefined_type()
  File "\Blender\4.0\scripts\addons\blenderbim\bim\module\model\data.py", line 258, in predefined_type
    predefined_type = relating_type.PredefinedType
  File "\Blender\4.0\scripts\addons\blenderbim\libs\site\packages\ifcopenshell\entity_instance.py", line 191, in __getattr__
    raise AttributeError(
AttributeError: entity instance of type 'IFC2X3.IfcFurnitureType' has no attribute 'PredefinedType'
```
2023-11-13 16:56:58 +05:00
Andrej730 48b237ab54 New context override method for setting viewport tools #3876 2023-11-13 15:51:50 +05:00
Andrej730 608b3e5401 DumpSlabPlaner.change_thickness to use si units #4004
It was providing project units to `geometry.add_slab_representation` resulting and then they were converted to project units once again during `geometry.add_slab_representation`.
2023-11-13 15:38:08 +05:00
Andrej730 c5d38227fc black format 2023-11-13 14:25:34 +05:00
Andrej730 e98ff136c2 Merge two Services sections in Services and Systems tab #4001
Two similar sections were needed in the old ui before we added tabs
2023-11-13 14:25:09 +05:00
Ryan Schultz 02ebc80525 closes #4006: automatically update the geometry of all the objects that have 'similar openings'. 2023-11-12 12:39:44 -06:00
Ryan Schultz 66431158b5 fixes #3908: Close the opening (bim.edit_openings) while having the opening selected 2023-11-12 10:11:13 -06:00
VDobranov dd044c8516 Update reference_structure.py
A mistype in docs: should be IfcRelReferencedInSpatialStructure instead of IfcRelContainedInSpatialStructure
2023-11-11 12:56:26 +01:00
Massimo Fabbro 55763ea7df Covering Tool now it is possible to add ceiling coverings from selected walls 2023-11-10 22:19:47 +01:00
Andrej730 8fe92e810f show mep regenerate and connecte elements for non-profile based elements 2023-11-10 16:28:44 +05:00
Andrej730 c26988b292 root.remove_product to remove IfcRelFlowControlElements 2023-11-10 12:10:22 +05:00
Andrej730 46e70c92c5 fixed issues with ports ui on undo
data.py doesn't update on every undo, so passed blender objects got invalidated on undo resulting in errors. changed blender objects to blender object names
2023-11-10 11:39:49 +05:00
Andrej730 325c3665d9 UI for assigning controls to flow elements #3981
Example - https://imgur.com/a/CZQIoHp
2023-11-10 11:18:52 +05:00
Andrej730 9a80dc14e9 api for assigning/unassigning flow controls #3981 2023-11-09 17:34:26 +05:00
Andrej730 6bda066e1b Fixed typo in control.assign_control, added tests 2023-11-09 15:33:31 +05:00
Andrej730 912b01587b tool.System.add_ports tests 2023-11-08 18:01:30 +05:00
Andrej730 5d4d953320 fixed issue placing ports on a bend if start segment is bending using Z- 2023-11-08 16:54:05 +05:00
Andrej730 11ed8cc787 fixed issue in add_ports mutating object's matrix
inherently modifying ports positions in some cases
2023-11-08 16:49:31 +05:00
Dirk Olbrich d1a7b99eda bbim docs: add user interface subsection, general workspace 2023-11-08 22:12:40 +11:00
Dirk Olbrich 85bdeaeef4 bbimdocs: reorder images folder in users section 2023-11-08 22:12:40 +11:00
Dirk Olbrich a5f0de4d19 bbim docs: reorder images folder in dev section 2023-11-08 22:12:40 +11:00
Dirk Olbrich cb3392ec70 bbim docs: use absolute path for icon images 2023-11-08 22:12:40 +11:00
Dirk Olbrich 1dbe42061d bbim doc: fix list indentation 2023-11-08 22:12:40 +11:00
Dirk Olbrich a024d5c07f bbim docs: fix minor warning in ux-guidelines 2023-11-08 22:12:40 +11:00
Dirk Olbrich ea5e3c30b6 bbim docs: update bbim version, copyright year 2023-11-08 22:12:40 +11:00
Andrej730 ebfc8ef619 remove BIMGroupProperties.is_adding attribute to avoid confusion
The problem with that attribute was that object's and project's group ui section were both using groups loaded to BIMGroupProperties.groups.

So you could run into situation when you try to load object's groups ui and it would show empty list because user never loaded the groups from the project's ui...

So it was either caching groups twice or just using same `is_editing` flag to check whether groups were previously loaded and I went with the single flag.
2023-11-08 15:13:49 +05:00
Andrej730 c0d8467154 define inherited ports attributes in bim.add_constr_type_instance 2023-11-08 14:19:36 +05:00
Andrej730 d0adbab9c2 fixed issue finding finding compatible fitting
it occured sometimes when segment's or fitting's PredefinedType/System were not defined
2023-11-08 12:21:50 +05:00
Andrej730 8e80f456cb fixed bug with system decoration data if no system were selected 2023-11-08 11:50:05 +05:00
Bruno Perdigão 61bd98e7db moved 'recreate_assembly' to tool/root.py 2023-11-07 18:28:43 -03:00
Bruno Perdigão 4bf0d9ccff added more tests 2023-11-07 18:19:42 -03:00
Bruno Perdigão 1e36ac8740 removed the pset and added group to all elements 2023-11-06 21:38:06 -03:00
Bruno Perdigão af864e8556 added test scenario for duplicating an aggregate 2023-11-06 12:15:31 -03:00
Andrej730 8cd9fb9015 test stairs calculated params 2023-11-06 15:56:33 +05:00
Andrej730 d9fdc0908a Nosing Lengths / Tread Gap for parametric stairs #3422
Example - https://imgur.com/d8PxLV4
2023-11-06 15:35:14 +05:00
Ryan Schultz a218ce5160 Select multiple arrays at one time, from various parts. Deselect non-compliant objects. 2023-11-04 11:35:30 -05:00
Igor.Sokolov b3a6b8e07f bf: IfcBSplineCurve is an isntance of abstract entity 2023-11-04 15:41:38 +01:00
Igor.Sokolov 52700452d9 bf: pass-valid-selected-enumeration.ifc 2023-11-04 15:41:38 +01:00
Igor.Sokolov aab011f7bf bf: pass-group-1-rels-IFC2X3.ifc failed 2023-11-04 15:41:38 +01:00
Igor.Sokolov 5f129e2357 bf: pass-attr-count-ok.ifc failed 2023-11-04 15:41:38 +01:00
Dion Moult 4e76f36af1 Black 2023-11-04 16:07:40 +11:00
Dion Moult 6f3ff51d91 Docs now mention historic builds 2023-11-03 22:45:42 +11:00
Dion Moult 0de0422c2e Minor fix 2023-11-03 22:45:42 +11:00
Andrej730 98de86e0ba Customize tread width for the first and last treads #3419
Available on all types of stairs, shouldn't break stairs previously created with BBIM.
Example - https://imgur.com/a/2wSueTM
2023-11-03 16:32:14 +05:00
Andrej730 142e41b3ad minor refactor 2023-11-03 16:32:14 +05:00
Andrej730 1e0dc7749d add force depsgraph update method 2023-11-03 16:32:14 +05:00
Andrej730 0f29de0391 skip black format on type manager template description for readibility 2023-11-03 16:32:14 +05:00
Andrej730 9933cc1b20 stair profile generation code refactor
hopefully it's now a bit more readable
2023-11-03 16:32:14 +05:00
Andrej730 fa6192e9bc Fixed stair calculated params not updating during edit (after 8b23c615c)
.data doesn't update on props change, so need to take data from props explicitly when BIMStairProperties.is_editing
2023-11-03 16:32:14 +05:00
Andrej730 bfd4559da8 move generate_stair_2d_profile to tool, add tests 2023-11-03 16:32:14 +05:00
ceegartner 01f52e069e Update unit.py - convert function, case issue
Hi,
I noticed an issue and suggest a fix:
Unit names from <si_conversions> are all lowercase, whereas project units extracted from the IFC files with <get_project_unit(...).Name> are uppercase. So the convert function didn't seem to work properly.
Hope this helps!
2023-11-03 11:47:44 +01:00
Dion Moult 2fbc9e4424 Forgot rabbit branding. 2023-11-02 15:15:04 +11:00
Dion Moult ba97da20eb New data purging IfcPatch recipe 2023-11-02 14:59:18 +11:00
Dion Moult 44f5be142f Fix #3963. Bind IFC separate to P hotkey and prevent separation on non-IFC meshes. 2023-11-02 13:03:56 +11:00
Dion Moult 2f951d352b Fix #3948. Bug where IfcTester PartOf facet didn't correctly read entity XML. 2023-11-02 12:29:05 +11:00
Andrej730 8b23c615c3 Fix issue with calculated params in stair ui
it was displaying incorrect data when stair was just loaded because it was relying on BIMStairProperties in ui.py
2023-11-01 17:33:38 +05:00
Dion Moult 7c694e5b3e Fix #3951. mats selector now supports IfcMaterialList. 2023-11-01 22:48:31 +11:00
Dion Moult 8eeb212003 See #3951. IfcCSV now supports list concatenation. 2023-11-01 22:47:30 +11:00
Dion Moult 7bf8d58cde Improve data type error reporting 2023-11-01 22:23:55 +11:00
Dion Moult b6e24559e5 Fix #3961. Improve UI so setting null now clears the value. 2023-11-01 18:04:44 +11:00
Andrej730 0d87d5927e bim.select_all_array_objects not to clear previous selection #3960 2023-11-01 10:53:25 +05:00
Dion Moult dfd5cc4728 See #3953. Fix bug where IDSes with a single enumeration value didn't validate. 2023-11-01 16:28:42 +11:00
Dion Moult 20b7ee009d Fix #3957. Fix bug where shared properties were not edited independently. 2023-11-01 15:18:57 +11:00
Dion Moult 19a3f56941 Fix #3958. Bug where reassigning type class would incorrectly assign occurrence classes. 2023-11-01 14:41:25 +11:00
Dion Moult 3b298d44c1 Fix regressions in mapped native swept disk handling 2023-11-01 14:16:12 +11:00
Andrej730 038d3bc41c fix future warning for xml.etree
The warning was: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
2023-10-31 16:24:41 +05:00
Andrej730 235e89ae14 remove blf.size deprecated dpi argument #3876
turn out it wasn't working for awhile now and in Blender 4.0 was completely removed
2023-10-31 16:19:42 +05:00
Andrej730 e2de9efc33 Move new Blender 4.0 Simulation section to Scene/Blender tab #3876 2023-10-31 15:57:54 +05:00
Andrej730 8126085037 Warning message on copying node graph on Blender 4.0+ #3876
As we're still looking for a workaround
2023-10-31 15:38:57 +05:00
Andrej730 bbe14834e4 Remove 3D shaders prefix #3876
In Blender 4.0 3D_* shaders are called without "3D_" prefix, otherwise it throws an error. Tested on Blender 3.6 - they work without "3D_" prefix too.
2023-10-31 15:27:43 +05:00
Andrej730 45f2d301b3 More context override fixes #3876 2023-10-31 15:18:33 +05:00
Andrej730 2ecd11d71f fixing test after 0d0b91e 2023-10-31 15:18:33 +05:00
Gorgious56 b42f072bd5 You can now eyedrop an object in the viewport to copy container when editing container 2023-10-31 11:14:54 +01:00
Ryan Schultz 3b3668eedf More IFC class suggestions 2023-10-30 22:51:55 -05:00
Dion Moult 7f7f353131 Disable batching for removal as it doesn't seem to help mostly from experience. Still testing. 2023-10-31 12:31:05 +11:00
Dion Moult 53594de1ff See #3955. PyPI release now specifies compatible Python versions. 2023-10-31 08:32:51 +11:00
Gorgious56 4fbbfb5191 You can now eyedrop an object in the viewport to copy class and predefined type when reassigning class 2023-10-30 15:04:37 +01:00
Gorgious56 4e1daea838 Clicking on an entry in the search field popup automatically validates and closes the popup
No need to click on "OK" anymore.
This is not a hacky workaround using the mouse position, it uses a signal sent to Blender to close the active popup
See https://blenderartists.org/t/programatically-close-pie-menu-2-79/1488807/2
re-committing since it seems I commited to the wrong branch last week
2023-10-30 14:19:01 +01:00
Andrej730 d8ff83da73 Replacing old context override method #3876 2023-10-30 15:14:34 +05:00
Andrej730 a7712a923f setup_pytest to find site-packages folder near sys.executable
Used to get errors running setup_pytest.py having python 3.10 installed on my pc (`sys_paths[-1]` was the system's python folder, not the blender's python).
2023-10-30 15:14:34 +05:00
Andrej730 01b5f8f237 Fixed #3949 2023-10-30 11:27:55 +05:00
Dion Moult b9ad15c50f Minor fix to Uniclass classification 2023-10-30 09:31:00 +11:00
Thomas Krijnen db06cff997 Update test file for case insensitivity. Thanks Igor. 2023-10-29 14:35:14 +01:00
Dion Moult f0028c0094 get_footprint_area now unions 2D polygons to prevent double counting 2023-10-28 15:54:45 +11:00
Dion Moult 1c954801b0 Fix #3939. Bug where IfcLabel data type was incorrectly used for longer text data. 2023-10-28 14:44:41 +11:00
Ryan Schultz 973e4f0064 Updated default JoinCriteria to accommodate new facet selector for statuses. 2023-10-27 11:24:49 -05:00
Andrej730 be5d291bd9 test creating mep transition 2023-10-26 17:21:42 +05:00
Andrej730 cbec56c2f0 ifc2x3 pset library - fix bunch of unit related vlaidation errors #3929 2023-10-26 15:54:34 +05:00
Dion Moult 880d0ba753 Minor fixes 2023-10-26 13:08:30 +11:00
Dion Moult db85689364 Add support for latest uniclass and add Uniclass July 2023 2023-10-26 13:08:30 +11:00
Sigma Dimensions (Yass) 48a0d8c508 fix displaying undefined or userdefined units in cost schedules 2023-10-25 15:01:52 +01:00
Sigma Dimensions (Yass) df4cd493ee fix displaying cost item totals 2023-10-25 13:54:13 +01:00
Massimo Fabbro 74132dcd49 New operator that creates a ceiling from cursor position in covering tool 2023-10-23 20:58:59 +02:00
Bruno Perdigão ef72cd3250 recreates assembly for array children objects 2023-10-23 15:46:14 -03:00
Andrej730 5cf1dd4249 fixed core tests after switch_representation changes 2023-10-23 17:25:07 +05:00
Andrej730 29bd30d3bf "Edit Profile" in BIM Tool for mapped representations
basically now "edit profile" will be shown in BIM Tool UI and will work from shift+e hotkey if the active element's representation is mapped (for example, if it has openings)
2023-10-23 16:50:05 +05:00
Andrej730 3f8a0a91b3 switch_representation to automatically switch to unresolved mapped representation
The cool thing about it now that it will automatically create a new mesh for "unresolved" representation if element has openings, otherwise it'll stick to the same mesh representation as the type object.

This fixed a few bugs:
- similar to b9a9abd but during extrusion profile edit
- applying void to the occurence used to remove the type and other occurences. Apparently it occured after 744c08e - previously we seems to rely on `ifcopenshell.geom.create_shape(settings, element)` to unresolve the representations. Though before 744c08e there still was an issue - it would apply the same opening to the all occurences and the type meshes but wasn't removing them.

Probably fixed a few other similar issues.
2023-10-23 16:49:56 +05:00
Andrej730 416a572664 switch_representation not to break with temporary mesh representations
I've found a bug that if you have some object that consists of extrusion and can be edited in profile edit mode, when you finish editing, it would remove the type object (and I guess the other occurences objects).

It happened because during edit mode it's using temporary mesh data and `switch_representation` would replace this temp mesh data with new representation and remove the old mesh data that might still used by the other occurences and the type.

The issue also was leading to a crash during `box.template_icon(icon_value=AuthoringData.data["type_thumbnail"], scale=5)` if you had BIM Tool thumbnail preview opened in the process - removing type object would make thumbnail icon become invalid leading to the crash.

Crash mentioned here: https://community.osarch.org/discussion/1753/bbim-two-door-types-with-connected-properties
2023-10-23 15:24:43 +05:00
Thomas Krijnen 388c72360d Use --start/end-group on linux to fix ld geomserver 2023-10-21 22:26:16 +02:00
Dion Moult b841afc2e4 Update beginners tutorial documentation with images from new UI. 2023-10-21 22:46:15 +11:00
Dion Moult f10d340254 You can now assign and unassign styles to materials 2023-10-21 15:23:55 +11:00
Dion Moult 0d0b91ee9b You can now specify a name when adding materials 2023-10-21 15:23:55 +11:00
Bruno Perdigão 4f1e59a613 improvements on dealing with sub-aggregates 2023-10-20 21:26:56 -03:00
Bruno Perdigão 5960e4153c wip: RefreshLinkedAggregate is working with IfcGroup 2023-10-20 14:34:03 -03:00
Ryan Schultz 8032333a17 Additional clarification on save and save as 2023-10-20 09:53:29 -05:00
Dion Moult 712ec6def3 Reorganise new stakeholders panel, move profiles into geometry tab. General UI polish. 2023-10-20 22:18:32 +11:00
Andrej730 0d43ef0736 option to set active system
Now it's possible to set in UI active system (currently it's done "select" button next to the system).

Also changed the elements that are going to be decorated with system decorator. Previously it was decorating all the mep elements in the projects which was very performance heavy on large projects.
2023-10-20 15:59:24 +05:00
Andrej730 b318509cba Merge systems UI into one
We had two very similar systems panels that were part of the old UI.
2023-10-20 14:00:32 +05:00
Dion Moult f3b541f00a Fix #3095. Very basic implementation of a new zones panel. 2023-10-20 17:51:48 +11:00
Andrej730 4f64dcdbd4 Fixed tests after selector syntax update 2023-10-20 11:06:10 +05:00
Dion Moult 68acf84e26 Fix #3901. Add configurable list concatenation support in IfcFM. 2023-10-20 13:38:17 +11:00
Dion Moult aaceb923ad Fix #3903. Bug where stairs started off with an empty mesh and had a representation added, resulting in an invalid empty point cloud.
Now stairs have should_add_representation=False when creating the IfcStairFlight, and the representation is updated explicitly, similar to how parametric doors and windows etc have their representations updated.
2023-10-20 12:28:18 +11:00
Dion Moult 074de2741a Fix regression from 744c08e where type products cannot have an instance specified in create_shape 2023-10-20 12:24:57 +11:00
Dion Moult 0e4bc320cb Adding / editing shading / rendering styles in the style manager now updates Blender materials 2023-10-20 10:26:35 +11:00
Andrej730 9e9412bec0 Forgot to fix test after 35d66f5 2023-10-19 18:10:31 +05:00
Andrej730 7e92471ac9 Fixed issue unlinking mesh objects
After d67eae5 delete_ifc_object is removing the meshes and it end up invalidating the unlinked object. Now mesh is copied before running delete_ifc_object
2023-10-19 17:05:14 +05:00
Andrej730 078a7eb290 Fix tests after 808ff54 2023-10-19 16:42:20 +05:00
Andrej730 df3876b438 Minor fix after a47c57c 2023-10-19 16:11:57 +05:00
Andrej730 d414de450b Fixed test after c34a9c5
Also fixed bug in the sheeter
2023-10-19 16:11:56 +05:00
Andrej730 9e89bb5044 Fixed test after 418444a 2023-10-19 13:22:06 +05:00
Andrej730 aa0c42e1ec Fixed test after 90b40ff 2023-10-19 13:05:25 +05:00
Andrej730 a4daa0e3d9 Fixed test after 88d96f7 2023-10-19 11:03:27 +05:00
Andrej730 162ac39570 Fixed test after 6e9639446 2023-10-19 11:03:27 +05:00
Andrej730 8c73fa69a1 Fixed #3907 after dd7a6a80e 2023-10-19 10:49:47 +05:00
Dion Moult 159eeeb3a4 You can now edit rendering styles in the style manager 2023-10-19 16:38:42 +11:00
Bruno Perdigão 66f735fde9 wip: refactor of RefreshLinkedAggregate. The operator triggers all the other linked aggregates deletion. 2023-10-18 21:36:04 -03:00
Bruno Perdigão 1a3aa7f031 IfcElementAssembly share a group instead of a pset 2023-10-18 20:43:41 -03:00
Ryan Schultz ac41a9e63a allow SI with CAD tools. 2023-10-18 17:07:29 -05:00
Andrej730 eb0873996f Added IfcZone to systems UI in IFC2X3 #3905
In IFC2X3 IfcZone is a subtype of IfcGroup but not subtype of IfcSystem (it become one after IFC4), therefore IfcZone wasn't presented anywhere in BBIM UI.
It's a bit confusing though to include IfcZone in systems when it's not actually a IfcSystem but having it in IfcGroups would be confusing too.
2023-10-18 17:13:22 +05:00
Andrej730 c85826ef2e Fixed #3901
It was throwing an error because was failing to write a list to an excel cell, now it's explicitly converting the value to string.

Python: Traceback (most recent call last):
  File "\blenderbim\bim\module\fm\operator.py", line 102, in execute
    writer.write_xlsx(filepath)
  File "\blenderbim\libs\site\packages\ifcfm\__init__.py", line 259, in write_xlsx
    cell = worksheet.cell(row=r, column=c, value=col)
  File "\blenderbim\libs\site\packages\openpyxl\worksheet\worksheet.py", line 247, in cell
    cell.value = value
  File "\blenderbim\libs\site\packages\openpyxl\cell\cell.py", line 218, in value
    self._bind_value(value)
  File "\blenderbim\libs\site\packages\openpyxl\cell\cell.py", line 187, in _bind_value
    raise ValueError("Cannot convert {0!r} to Excel".format(value))
ValueError: Cannot convert ['USE TYPE CATALOG'] to Excel
2023-10-18 16:40:07 +05:00
Andrej730 627cf63a4c ifcfm symlink to dev environment setup script 2023-10-18 16:07:27 +05:00
Andrej730 744c08e13e bim.switch_representation to switch to exact representation
previously it was switching to the first representation that matches the context, so it wasn't possible to switch to the second one if you had more than 1 representation in the same context

using always both element and representation in `geometry.import_representation` so it will import the exact representation and not the first one found by `ifcopenshell.geom.create_shape`
2023-10-18 15:48:08 +05:00
Andrej730 dd7a6a80eb activate_drawing to prioritize already active representation
If there are multiple representations in the same subcontext, when it was searching for the representation for some specific subcontext, it would previously always switch to the first representation from the list, now it's going to prioritize the one that's already active.
2023-10-18 15:48:01 +05:00
Andrej730 ab807e3b9b bim.create_all_shapes info message 2023-10-18 12:21:41 +05:00
Andrej730 c35be50c83 Bump build version to fix #3889 2023-10-18 11:10:04 +05:00
Bruno Perdigão 37ab9c80e3 Duplication now recreates connections path #3770 2023-10-17 18:45:14 -03:00
Andrej730 7ff98d2918 Some UI to mark booleans as manual #3709
Currently it allows only to either set all object's booleans to be marked as manual or all of them marked as automatic, can't change some specific boolean.

Short demo - https://imgur.com/a/bczv35N
2023-10-17 18:19:45 +05:00
Andrej730 35d66f5d8c move to tools methods for working with manual booleans #3709
Also fixed a bug adding boolean when pset is already added and representation type in add_boolean

```
  File "\addons\blenderbim\tool\ifc.py", line 201, in execute
    IfcStore.execute_ifc_operator(self, context)
  File "\addons\blenderbim\bim\ifc.py", line 336, in execute_ifc_operator
    result = getattr(operator, "_execute")(context)
  File "\addons\blenderbim\bim\module\model\opening.py", line 534, in _execute
    data = json.loads(pset["Data"])
  File "\addons\blenderbim\libs\site\packages\ifcopenshell\entity_instance.py", line 248, in __getitem__
    if key < 0 or key >= len(self):
TypeError: '<' not supported between instances of 'str' and 'int'
```
2023-10-17 18:13:54 +05:00
Andrej730 3f018a4195 localize mathutils dependency in tests #3895
replaced shapebuilder with general ifcopenshell code in `test_add_boolean` (the only place besides `test_shape_builder` where it was used), that way mathutils dependency in tests is localized only to `test_shape_builder.py`.

added test-safe option to makefile, so github workflow would ignore `test_shape_builder` tests for now and it wouldn't interrupt the entire workflow
2023-10-17 15:53:26 +05:00
Andrej730 578e15adb2 refresh_aggregate to show time it took
since this can get very time consuming on large projects
2023-10-17 15:07:43 +05:00
Andrej730 c4474455e9 Fix poll error after 3de9915
The error was
Traceback (most recent call last):
  File "\blenderbim\bim\module\model\covering.py", line 64, in poll
    return element.is_a("IfcCovering")
AttributeError: 'NoneType' object has no attribute 'is_a'
2023-10-17 15:07:43 +05:00
Dion Moult 8f43854cbf Minor fix 2023-10-17 20:47:39 +11:00
Thomas Krijnen 787149da13 Regen express rule code: lowercase str comparison in express rule generated code 2023-10-17 11:04:46 +02:00
Thomas Krijnen 3b31f6932a Compile IFC4X3_ADD2 express rules 2023-10-17 09:50:39 +02:00
Andrej730 6c9e130ca8 small fix f38952dc5 #3898 😬 2023-10-17 10:47:52 +05:00
Bruno Perdigão 86a234d17e Changed operator name 2023-10-16 22:32:09 -03:00
Bruno Perdigão f68baee5c3 small deletions 2023-10-16 22:17:22 -03:00
Bruno Perdigão 0028fd3e9c ifc_duplicate_operator now remove the connections with old objects. Similar solutions presented in PR #3789 2023-10-16 15:39:38 -03:00
Bruno Perdigão f5f9862b78 Fix #2187. ifc_duplicate_operator now recreates the IfcElementAssembly structure into a new Assembly 2023-10-16 15:31:56 -03:00
Andrej730 f38952dc51 small refactor 2023-10-16 16:23:48 +05:00
Andrej730 24eb149221 Support other voiding IfcFeatureElementSubtraction elements #3889
Support other voiding IfcFeatureElementSubtraction besides IfcOpeningElement.
2023-10-16 15:31:53 +05:00
Andrej730 ce8598a0b4 Fixed issue after 19345ff
It wasn't considering that EnumerationReference could be None
2023-10-16 15:31:53 +05:00
Thomas Krijnen fb9cf75412 #3889 Apply handling of openings on IfcFeatureElementSubtraction generically 2023-10-16 11:02:40 +02:00
Andrej730 68f5df73b9 black formatting 2023-10-16 12:21:20 +05:00
Andrej730 e068c523ec Keep placement axes recalculating profiles #3879 2023-10-16 12:19:18 +05:00
Andrej730 aa182bf047 small fix add_profile_representation - use of undefined variables 2023-10-16 11:59:33 +05:00
Ryan Schultz 6e9639446d Add a preference for particular app to open sheet layout 2023-10-15 20:04:53 -05:00
Bruno Postle c48c1c3b32 BlenderBIM minor fix after 7107a91 2023-10-15 21:15:32 +01:00
Dion Moult 14224ac538 Fix #3870. Bug where element filtering wasn't initialised properly when loading a camera for the first time.
Raster_x/y would only be set after the handler triggers. This is no longer necessary with the new explicit width / height properties.
2023-10-15 22:23:10 +11:00
Dion Moult 58be92d3fc New verbose option in util get_pset(s) which lets you get ID and class for complex processing. 2023-10-15 08:57:37 +11:00
Bruno Postle 7107a91f6f BlenderBIM keep camera position on git switch
New 'zoom extents' behaviour on IFC load is unwanted when switching
between git revisions
2023-10-14 21:54:16 +01:00
Thomas Krijnen 438ed22f8f Merge pull request #3888 from isma3lMB/v0.7.0
Adding support for non ascii characters when reporting
2023-10-14 16:00:18 +02:00
isma3lMB a9dfc9a9fd Adding support for non ascii characters when reporting 2023-10-14 15:31:33 +02:00
Thomas Krijnen f8b09b3525 Update build-deps.cmd: proj compilation 2023-10-13 22:34:35 +02:00
Massimo Fabbro f1ab02b311 Fix bug in covering/space tool with matrix global and local 2023-10-13 22:03:43 +02:00
Bruno Perdigão 4e833e26ca wip: DuplicateMoveAggregate now calls DuplicateMove function and removes code duplication 2023-10-13 14:41:21 -03:00
Dion Moult 25df2f6414 See #3884. Rewrite native geometry handling with a much more robust approach fixing a number of invalid coordinates and simplifying things. 2023-10-13 23:40:23 +11:00
Dion Moult 42719d3fe3 Fix bug where native meshes had normal smoothing enabled by default 2023-10-13 23:40:23 +11:00
Dion Moult 1f6d23c19c Minor fixes to placement utilities for getting mapped item matrixes 2023-10-13 23:40:23 +11:00
Thomas Krijnen 94db9ec522 Add IFC4X3_ADD2 schema 2023-10-13 11:51:05 +02:00
Dion Moult a47c57c22c First draft of style manager panel 2023-10-13 17:38:55 +11:00
Dion Moult 8f4bc0ea00 Material manager panel now moved to geometry tab 2023-10-13 17:37:24 +11:00
Dion Moult dd70b09fb1 Representation items panel now shows styles and layers 2023-10-12 22:56:36 +11:00
Dion Moult c930050da6 Accommodate bug in Revit where mapped representations were missing... well, a representation map. 2023-10-12 22:56:36 +11:00
Dion Moult 55a7a72e61 Minor bug fixes with error message when selecting objects in layers without objects 2023-10-12 22:56:36 +11:00
Dion Moult ca2ae36d41 Modernize zone and type table mappings for COBie 2.4 with Emma Hooper 2023-10-12 22:56:36 +11:00
Thomas Krijnen 81b4e42ca2 Use schema_identifier for schema and express rule validation. See #3126 2023-10-12 10:37:44 +02:00
Massimo Fabbro 55e61b55d8 better UI for covering tool 2023-10-12 05:58:52 +02:00
Massimo Fabbro a99529cb1e fix generate space and covering where objects weren't created in the right location 2023-10-12 05:58:52 +02:00
Dion Moult bf43efe509 Begin drafting out a new representation items panel for managing styles and layers properly 2023-10-11 23:26:48 +11:00
Vukas Pajic da7f5b015b add missing attributes in ids.parse 2023-10-11 10:06:54 +02:00
Massimo Fabbro 3de9915389 Add generate flooring from cursor and regen (#3874) 2023-10-11 09:15:36 +11:00
Dion Moult 418444a196 Fix #3873. Regression due to new importing logic. 2023-10-11 09:12:00 +11:00
Dion Moult 171251b27d See #1619. Fix issue where copying non-templated properties didn't work. 2023-10-11 08:53:53 +11:00
Ryan Schultz 9fef920a6f Further clarify the bim.link_ifc command 2023-10-10 13:43:56 -05:00
Dion Moult 5bff837a61 Minor fix 2023-10-10 22:21:32 +11:00
Dion Moult 05f6f4efab Manual booleans are now tracked via a Pset instead of arbitrary class conventions which should fix a bunch of issues. 2023-10-10 17:33:00 +11:00
Dion Moult e4f5b0e3d8 Write documentation for placement utility 2023-10-10 10:56:28 +11:00
Dion Moult 49b733f660 See #3817. WARNING: fundamental change. Standardise prioritisation of all context permutations when loading occurrences and types. 2023-10-09 23:21:09 +11:00
Dion Moult 36ed618adf You can now federate FM spreadsheets using the Blender UI 2023-10-09 17:26:45 +11:00
Dion Moult 48042011e2 Merge pull request #3860 from IfcOpenShell/Representation_Utilities_more_functions
Adding "Manually Save Representation" and bim.get_representation_ifc_…
2023-10-09 09:58:58 +11:00
Andrej730 0e1939a871 Minor fix #3862 2023-10-08 21:32:34 +05:00
Ryan Schultz bea1e61739 Adding "Manually Save Representation" and bim.get_representation_ifc_parameters back to Representation Utilities panel
from: https://github.com/IfcOpenShell/IfcOpenShell/commit/3a812a9ec156818061c01bd5b2ac2c2bee09faf1#r123820129
2023-10-08 09:24:18 -05:00
Ryan Schultz 72cd82f450 fixed error when creating new walltype in IFC2x3 2023-10-07 10:25:22 -05:00
Massimo Fabbro befa059591 Merge pull request #3838 from maxfb87/covering_tool
Covering tool (see #3754)
2023-10-07 14:20:27 +02:00
Bruno Postle 7229f7271c BlenderBIM make fca90e9 optional
setup_viewport_camera() does a 'zoom extents' on IFC import.
Create a should_setup_viewport_camera option (default True)
2023-10-06 22:34:43 +01:00
Andrej730 9c5970e757 fixed issue with placing end port for a bend 2023-10-06 17:30:01 +05:00
Andrej730 2fe3f0a9df system decorations - indicate both directions flow 2023-10-06 17:30:01 +05:00
Dion Moult 3929f02e94 Fix #3843. Regression where IfcMaterialList UI didn't show list of materials. 2023-10-06 22:43:56 +11:00
Andrej730 1abf80c310 Minor fix after b9a9abd30 2023-10-06 16:03:40 +05:00
Andrej730 2c18c89807 revert flow directions icons to arrows 2023-10-06 16:01:46 +05:00
Andrej730 1b81fa5aa1 Minor fix after 78c748df5
RuntimeError: Error: Registering panel class: parent 'BIM_PT_tab_placement' for 'BIM_PT_placement' not found
2023-10-06 15:31:41 +05:00
Hilko baa08b3221 Update build-deps.cmd 2023-10-06 12:16:51 +02:00
Andrej730 b9a9abd30d Fixed adding opening to meshes of all occurences for non material based representations
Mentioned in #3817
2023-10-06 15:11:14 +05:00
Andrej730 33536957d8 Moving some code to tool.Geometry 2023-10-06 15:11:14 +05:00
Dion Moult d092fd45ba You can now select coloured objects in a colourscheme. 2023-10-06 16:51:50 +11:00
Dion Moult 78c748df5d New placement panel to consolidate placement data in geometry tab 2023-10-06 15:25:51 +11:00
Dion Moult 3d76de3041 New geometry tree documentation picture and minor documentation improvements including mention of COBie 2.4 legacy mode in IfcFM. 2023-10-06 13:05:38 +11:00
Dion Moult ed3e9f3347 New documentation for shape utility 2023-10-06 13:04:54 +11:00
Dion Moult eb836436b9 Implement projected surface area calculation function in util.shape 2023-10-06 13:04:34 +11:00
Dion Moult c34a9c52d0 New drawing width / height / depth / raster DPI controls 2023-10-06 10:45:54 +11:00
Dion Moult 88d96f7d57 You can now easily create orthographic and perspective model drawings from a preset 2023-10-06 10:44:51 +11:00
Dion Moult 69e447be1c Active drawing panel moved from camera properties to drawing tab. 2023-10-06 08:17:03 +11:00
Massimo Fabbro df09acfa31 Merge branch 'v0.7.0' into covering_tool 2023-10-05 21:23:11 +02:00
Massimo Fabbro 6343f77c0d Minor spatial refactor 2023-10-05 21:17:25 +02:00
Thomas Krijnen 285fc2269e #3852 Update pyproject.toml 2023-10-05 15:52:59 +02:00
Andrej730 68a1da9190 test for model.get_manual_booleans() #3709
added test that model.get_manual_booleans will ignore IfcBooleanClippings until we find some other solution to distinguish automatic and manual clippings. And some refactor along the way.
2023-10-05 18:38:46 +05:00
Andrej730 ceae7d4fdb DumbWallJoiner to work with IfcBooleanResult correctly #3831
It wasn't detecting extrusion as part of IfcBooleanResult and was using default wall data as fallback.

Occured after 0044ef5
Solves #3831
Related to #3709
2023-10-05 17:31:24 +05:00
Dion Moult 371daa6c80 Revise COBie 2.4 mappings for facility, floor, and some of space worksheet in collaboration with Emma Hooper 2023-10-05 22:49:52 +11:00
Dion Moult 948993e066 Fix #3845. Select similar for predefined type now takes into account inheritance. 2023-10-05 22:47:12 +11:00
Andrej730 ec4f0e5ad6 Fixed issue applying array with Sync Children #3822 2023-10-05 15:32:45 +05:00
taylor ef56c6ce7e Fixed model reference 2023-10-05 10:17:03 +02:00
Dion Moult 3c02da416e Georeference module now supports IFC2X3 georeferencing / conversion utilities. 2023-10-05 16:15:28 +11:00
Dion Moult 6660bf7618 Document geolocation util and add support for ePSet IFC2X3 fallbacks. 2023-10-05 16:15:28 +11:00
Dion Moult 000e5ec29a Merge pull request #3835 from c4rlosdias/v0.7.0
Fix problem in facets.py (IfcTester)
2023-10-05 11:39:47 +11:00
Dion Moult ef8f4df4ab Fix #3841. Bump IOS. 2023-10-05 09:57:03 +11:00
Andrej730 dff70f2608 bim.flip_object #3803
Added new operator bim.flip_object that flips the object by flipping two of its axes and keeps the original placement.

Currently it can be found either from F3 search or from Shift-F hotkey for IfcBeam and IfcColumn in BIM tools.
2023-10-04 18:20:17 +05:00
Andrej730 0d7967ff62 .reg file for #3778
Forgot to commit the .reg file...
2023-10-04 15:13:57 +05:00
Andrej730 4fe459dab6 Fixed typo 2023-10-04 09:47:38 +05:00
Thomas Krijnen 0e5e1f7873 Option to write Earth-Centered Earth-Fixed glTF 2023-10-03 21:26:11 +02:00
Dion Moult 82d4829c83 Clean up IfcFM's Basic preset to be more true to IFC rather than follow naming schemes from stuff like COBie 2023-10-03 21:21:28 +11:00
Dion Moult a24fab6d92 You can now select and bulk process multiple models using IfcFM in Blender. 2023-10-03 21:21:28 +11:00
Dion Moult 748055dcf1 New IfcPatch recipe to fix Revit bug with occurrence based classifications 2023-10-03 21:21:28 +11:00
Dion Moult 3904162360 New IfcPatch recipe to fix Revit bug with hardcoded Uniformat classification 2023-10-03 21:21:28 +11:00
Andrej730 7ca24ede4c IfcSverchok docs update urls 2023-10-03 10:50:56 +05:00
Ryan Schultz 1e59b10479 Merge pull request #3820 from brunoperdigao/fix-duplicate-agg-pset-for-new-objs
Fixed a bug where the refresh aggregate operator was not working afte…
2023-10-02 15:14:05 -05:00
Massimo Fabbro cda61bff5b Refactor create_space operator and better UI for covering tool 2023-10-02 22:13:03 +02:00
Massimo Fabbro 09a9753ca7 refactor create spaces from walls 2023-10-02 22:13:03 +02:00
Massimo Fabbro 1621449143 Add predefined type to AuthoringData 2023-10-02 22:13:02 +02:00
Ryan Schultz d0ef7f69b1 fix #3792 2023-10-02 14:56:17 -05:00
c4rlosdias 3df95b8970 Merge branch 'v0.7.0' of https://github.com/c4rlosdias/IfcOpenShell into v0.7.0 2023-10-02 13:49:32 -03:00
c4rlosdias ddd4b0e262 Fix problem in getpsets(facet.py) and added descriptions to specifications (IfcTester) 2023-10-02 13:49:27 -03:00
Carlos Dias 6b05b6e7fb Merge branch 'IfcOpenShell:v0.7.0' into v0.7.0 2023-10-02 12:58:10 -03:00
Andrej730 9dd728ce7e Fixed error creating a door type / window types after 8f6be60c6 2023-10-02 17:32:56 +05:00
Andrej730 90b40ff0dc Getting drawing group more precisely
Previously it was conflicting with other possible groups assigned to the object. It's now even more important since we're actively using groups to save search queries.

Example error caused by this issue - during drawing activation if you had 2 IfcGroups on the drawing element:
draiwng's IfcGroup RelatedObjects attribute was updated, then inverse attrtibute `drawing.HasAssignments` order was updated too (DRAWING IfcGroup now would be positioned second after IfcGroup for search query) and it was leading to errors during filtering current drawing annotations
2023-10-02 16:55:38 +05:00
Andrej730 3c27c52c9f Small fix for 05d4dc566 2023-10-02 15:38:26 +05:00
Andrej730 05d4dc5666 Rever IFC Project
https://i.imgur.com/ajQiK8D.png
2023-10-02 15:30:32 +05:00
Andrej730 edaabf5bd2 Fixed #3829 occured after ae45e6b
similar_openings wasn't reset on each iteration causing moving unrelated openings
2023-10-02 11:44:31 +05:00
Andrej730 ad79c63a37 Fixed #3832 2023-10-02 10:57:24 +05:00
Sigma Dimensions (Yass) 9461bf2129 fix f2097c0 2023-09-29 17:30:33 +01:00
Sigma Dimensions (Yass) f2097c0c5f importing csv cost schedules now allows using selector queries for effortless product assignments to cost items, and add new ods and csv format templates (in french) 2023-09-29 16:10:16 +01:00
Dion Moult d838e1808d IfcFM can now be used to federate multiple spreadsheets together 2023-09-29 23:03:58 +10:00
Dion Moult 5ed54d9e7c Revise COBie 2.4 contact table mapping in collaboration with Emma Hooper 2023-09-29 23:03:58 +10:00
Andrej730 78aba1c7e4 Workaround for #3778 2023-09-29 15:28:11 +05:00
Andrej730 3faaee80ec copy_deep to always pass exclude_callback to the recursion
It wasn't passing the exclude_callback if attribute of the copied element wasn't a tuple, resulting in duplicated named profiles in case if you'd copy a IfcBooleanClippingResult #3810

For example, how copy_deep of IfcProductDefinitionShape with boolean clipping previously would work:
V IfcShapeRepresentation - copied with exlude_callback (part of .Representations[])
V IfcBooleanClippingResult - copied with exlude_callback (part of .Items[])
X IfcExtrudedAreaSolid - copied without exlude_callback becuase it's part of .FirstOperand (not an array) and we have IfcIShapeProfileDef duplicated

Case without booleanclippings:
V IfcShapeRepresentation - copied with exlude_callback (part of .Representations[])
V IfcExtrudedAreaSolid - copied with exlude_callback, since it's part of .Items[], IfcIShapeProfileDef not duplicated
2023-09-29 09:29:25 +05:00
Andrej730 a847b8f4e4 bim.remove_opening not to force Model/Body/Model_view
Now it won't be forcing Model/Body/Model_view representation on the objects if some other context is active for the object.

Indirectly solves #3817
2023-09-28 18:51:27 +05:00
Dion Moult 24170a8a16 Ship with fallback IFC2X3 georeferencing pset 2023-09-28 23:07:43 +10:00
Massimo Fabbro 5438331fe1 fix generate spaces from walls bug 2023-09-27 18:52:49 +02:00
Carlos Dias 3c957e0cbe Merge branch 'IfcOpenShell:v0.7.0' into v0.7.0 2023-09-27 10:55:52 -03:00
Andrej730 10672f3e1a Print unused elements stats / purge unused elements
Added to Purge Data section in Quality Control some tools - https://i.imgur.com/Nz3YoiH.png

1) Print unused elements - useful to investigate how much unused data you have in IFC file.
https://i.imgur.com/9Fkn0JD.png

2) purge unused elements by ifc class, it's doing it in pretty naive way and can be dangerous, so maybe it should be moved to debug section.
2023-09-27 15:42:31 +05:00
Andrej730 fa90e420eb info message for amount of purged elements 2023-09-27 13:55:56 +05:00
Dion Moult 347bb2df4b Introductory docs written for IfcFM 2023-09-27 18:22:02 +10:00
Dion Moult 986ffe66f8 New introduction section in IOS docs 2023-09-27 18:22:02 +10:00
Andrej730 c1bedec354 Minor fix after 22edbdd
Error was:

TypeError: EnumProperty(..., default='cobie'): not found in enum members
Exception in module register(): \3.6\scripts\addons\blenderbim\__init__.py
Traceback (most recent call last):
  File "\Blender\3.6\scripts\modules\addon_utils.py", line 369, in enable
    mod.register()
  File "\3.6\scripts\addons\blenderbim\__init__.py", line 42, in register
    blenderbim.bim.register()
  File "\3.6\scripts\addons\blenderbim\bim\__init__.py", line 190, in register
    bpy.utils.register_class(cls)
ValueError: bpy_struct "BIMFMProperties" registration error: 'engine' EnumProperty could not register (see previous error)
2023-09-27 12:09:44 +05:00
Dion Moult 182b6c7b07 IfcFM now supports writing to Pandas Dataframes 2023-09-27 14:18:48 +10:00
Dion Moult 22edbddd84 You can now interact with IfcFM via CLI 2023-09-27 14:17:46 +10:00
Dion Moult 50f6f44d26 You can now specify empty formatting for IfcCSV via CLI 2023-09-27 14:16:43 +10:00
Dion Moult e93a697179 Fix #3788. Fix crash when opening drawing SVGs using webbrowser module which is not recommended and the file is on a Dropbox synced external drive. Now replaced with generic os.startfile / xdg-open / open commands. 2023-09-27 11:50:52 +10:00
Sigma Dimensions (Yass) f1a5805b1c fix loading animation color scheme 2023-09-26 18:33:52 +01:00
Sigma Dimensions (Yass) 126f530af1 run black and forgotten calender utils 2023-09-26 16:44:35 +01:00
Sigma Dimensions (Yass) 5dfbbb8d96 maintain tasks bar visual property state when tasks properties are reloaded 2023-09-26 16:42:35 +01:00
Sigma Dimensions (Yass) 6962e505f9 hide spaces when creating an animation 2023-09-26 16:38:33 +01:00
Sigma Dimensions (Yass) 5c2523e752 fix warning statement when there are no saved animation color schemes 2023-09-26 16:36:48 +01:00
Sigma Dimensions (Yass) 635dff73b4 fix typo 2023-09-26 16:35:31 +01:00
Sigma Dimensions (Yass) c85e4e7ceb fix missing task types for animations color scheme 2023-09-26 16:35:00 +01:00
Sigma Dimensions (Yass) 7ed4301c6c fix tasks not displaying derived calendar 2023-09-26 16:29:53 +01:00
Andrej730 1193e7025a system decorations - live time update
Decoration data is now updating in live time, caching some parts in Data for performance. Real time update is needed because Data doesn't allow update on objects positions change and later will need real time update for viewport orientation data.
2023-09-26 17:08:39 +05:00
Andrej730 cc1ee19115 Add ports to MEP bends/transitions types instead of occurences 2023-09-26 15:19:49 +05:00
Andrej730 e975eac4a7 system decorations to show flow direction 2023-09-26 11:47:10 +05:00
Andrej730 779fc35228 settings flow direction without jumping to ports
https://imgur.com/a/F00tG7g
2023-09-26 11:47:10 +05:00
Dion Moult 8e59282fe0 Possible optimisation by caching in IfcTester property checks 2023-09-26 16:03:10 +10:00
Bruno Perdigão 11c8d47909 fixed a bug where the refresh aggregate operator was not working after adding new objects to the parent aggregate 2023-09-25 22:55:56 -03:00
Claudio Benghi 2661999f3e Fixed most issues with IDS auditing 2023-09-26 11:06:58 +10:00
Ryan Schultz e4bfb05875 proposed fix for #3792 2023-09-25 10:32:06 -05:00
Massimo Fabbro fe14988d50 Merge pull request #3790 from maxfb87/new_covering_tools
New covering tools (see #3754)
2023-09-25 16:03:56 +02:00
Massimo Fabbro d45bef5e70 Merge branch 'v0.7.0' into new_covering_tools 2023-09-25 15:01:03 +02:00
Andrej730 82d03b98c6 Descriptions for add_representation conversion methods 2023-09-25 16:32:48 +05:00
Andrej730 9c1ecf3f2c draw calculate_all_quantities hotkey in bim tool ui
hotkey was already there, it just wasn't added to UI

https://i.imgur.com/nar5WYI.png
2023-09-25 16:32:48 +05:00
Andrej730 8f6be60c6e recalculate fills on applying changes to ifc windows / ifc doors
previously if you'd move the window and then change it's parametric data and try to apply it, opening's position wouldn't be updated
2023-09-25 16:32:48 +05:00
Andrej730 81a1bd9206 Moved common duplication operators code to DuplicateMove
Now OverrideDuplicateMoveLinked allways will be in sync with OverrideDuplicateMove.

Also fixed the issue when DuplicateMoveLinked for non ifc elements worked the same was DuplicateMove (it was copying mesh data when it's not suppose to).
2023-09-25 16:32:48 +05:00
Andrej730 9f7dffb29d replace Drawing.remove_object_data with more general method 2023-09-25 16:32:47 +05:00
Dion Moult eee799bfc4 Purge IfcCOBie deps from build 2023-09-25 19:24:01 +10:00
Dion Moult 9665adb61d Fix #3793. Bug where flipping a wall with generic connection relationships would fail. 2023-09-25 08:34:48 +10:00
Sigma Dimensions (Yass) e40019f3cb resources code cleanup 2023-09-24 19:02:35 +01:00
Sigma Dimensions (Yass) b2f95bfa60 change tests due to new class assignment workflow ref commit 808ff54 2023-09-24 18:45:12 +01:00
Bruno Perdigão be2c7a62fd remove connections with old objects when duplicating aggregates 2023-09-24 22:23:55 +10:00
Dion Moult 38f5468f19 We now support separating IFC meshes. 2023-09-24 15:45:22 +10:00
Dion Moult 31dcbc0159 Splitting by edge now resolved mapped representations, voided, and non-mesh geometries 2023-09-24 15:45:22 +10:00
Sigma Dimensions (Yass) bd81320c08 fix parametric duration/ resource update 2023-09-24 04:39:30 +01:00
Dion Moult 0707f37247 Minor fix during loading arrays 2023-09-24 13:18:32 +10:00
Dion Moult 0993736cea Fix #3791. Add isodate as an optional dependency to ifcopenshell-python. 2023-09-24 13:14:56 +10:00
Sigma Dimensions (Yass) cc3e2204e2 improved template for resource csv imports 2023-09-24 03:17:39 +01:00
Sigma Dimensions (Yass) 8ac5f0318b fix location search filter 2023-09-23 23:35:17 +01:00
Sigma Dimensions (Yass) 270a61e73a bring back filter operators into new Filter subpanel and change filter by storey to filter by container 2023-09-23 21:26:58 +01:00
Massimo Fabbro 1c057b1ce1 Add new covering tool. Mock up and initial functions 2023-09-23 18:09:59 +02:00
Sigma Dimensions (Yass) e74e824417 Proposal to use resource's parent cost, reducing manual insertions 2023-09-23 16:04:01 +01:00
Dion Moult 73d1de5dcf New debug feature to override the display type. 2023-09-23 14:51:27 +10:00
Dion Moult 4549be0d05 Autodetect dense meshes to make it faster when loading so users don't need to go into advanced mode. 2023-09-23 14:51:27 +10:00
Andrej730 e3f2f2175d Moving common code for duplication operators 2023-09-22 16:37:50 +05:00
Andrej730 a604cf2b2a Duplicate the array if all it's elements are selected #3763
Demo - https://imgur.com/a/0wYZOPl
2023-09-22 16:37:49 +05:00
Andrej730 d6b4c1f454 Setup arrays constraints on loading .ifc #3753 2023-09-22 13:56:55 +05:00
Andrej730 d3258693b2 Clear constraint and transform lock on duplicating array child object
Previously it was locked even though it's not part of an array anymore.
2023-09-22 13:56:55 +05:00
A. R. S 9eba3b6eaa Try to get unit from EnumerationReference for IfcPropertyEnumeratedValue 2023-09-22 17:41:05 +10:00
Dion Moult 7b75364feb Refactor IfcFM to make it easier to exclude things 2023-09-22 17:17:15 +10:00
Dion Moult 4a4a0f09ef Finally purge IfcCOBie to be superseded by IfcFM 2023-09-22 17:04:22 +10:00
Andrej730 6d14c2d448 removing arrays if all array elements are selected #3781
I think there is still some space to improve but it should cover the main problem with need going to array section to remove it
Demo - https://imgur.com/a/9Z3t5Q8
2023-09-22 11:25:56 +05:00
Andrej730 57edd47ed7 Fixed error editing pset with prop with empty prop.NominalValue
Traceback:
```
Error: Python: Traceback (most recent call last):
  File "\blenderbim\bim\module\pset\operator.py", line 103, in execute
    self.load_from_pset_data(pset)
  File "\blenderbim\bim\module\pset\operator.py", line 226, in load_from_pset_data
    value = prop.NominalValue.wrappedValue
AttributeError: 'NoneType' object has no attribute 'wrappedValue'
```
2023-09-22 10:25:51 +05:00
Massimo Fabbro aefcedf754 Add model test about manual booleans 2023-09-21 23:19:47 +02:00
Massimo Fabbro 2c685c846f Added calculating quantities function for Qto_DuctSegmentBaseQuantities and Qto_DuctFittingBaseQuantities 2023-09-21 23:19:24 +02:00
Ryan Schultz 6536f7b56b small fix for 9e67565 2023-09-21 12:58:16 -05:00
Vukas Pajic 9d3881b00e typo 2023-09-21 16:14:37 +02:00
Vukas Pajic baffbd6a32 Update ids validation
see https://github.com/IfcOpenShell/IfcOpenShell/issues/2933
2023-09-21 13:27:38 +02:00
Sigma Dimensions (Yass) 9e4702c102 small fix when calculating resource work 2023-09-21 06:04:24 +01:00
Dion Moult b63f3f335c Autogenerate API docs for more modules. 2023-09-21 13:33:26 +10:00
Dion Moult 29b0bcb6b9 Forgot to commit BCF docs 2023-09-21 13:23:43 +10:00
Dion Moult 62fa0bb218 Migrate more documentation to the official Sphinx docs and mention IfcOpenShell-WASM as an installation option 2023-09-21 13:21:43 +10:00
Ryan Schultz 9e67565c71 Refresh aggregate from selecting a part 2023-09-20 08:54:04 -05:00
Andrej730 dee4cf591e mep system decorators - basic implementation
All it does currently it draws all MEP elements connections in viewport. It also highlights with green color all elements connected to the active object

Demo - https://imgur.com/a/haAQeWt
2023-09-20 15:28:06 +05:00
Andrej730 bc5d6ee113 fixed error in api.system.disconnect_port
Error was:
TypeError: can only concatenate tuple (not "list") to tuple
2023-09-20 15:28:05 +05:00
Andrej730 5af3b537da get_viewport_context to also return space 2023-09-20 15:28:05 +05:00
Andrej730 4b159d400c bim.draw_system_arrows updated for ifc4 2023-09-20 15:28:05 +05:00
Sigma Dimensions (Yass) f3c012660a improve pset editing workflow and use refactored core and tool functions 2023-09-20 01:22:18 +01:00
Sigma Dimensions (Yass) b5b8b5df26 cascade schedule when adding a sequence relationship 2023-09-20 01:15:06 +01:00
Sigma Dimensions (Yass) 6d38d9b538 fix count_working_days when the start and finish are the same same hours 2023-09-20 01:11:42 +01:00
Sigma Dimensions (Yass) ef11ae6540 fix calculating critical path to consider:
- parent tasks with sequence assignments #3772
- tasks that are constrained by a schedule start
2023-09-20 01:10:34 +01:00
Sigma Dimensions (Yass) a3802c25c0 fix cascading schedule when parent tasks have sequence relationships #3772 2023-09-20 01:05:19 +01:00
Andrej 377bcfe6da Merge pull request #3732 from brunoperdigao/fix-refresh-aggregate-rotation 2023-09-19 23:57:52 +05:00
Dion Moult 63a5c0986f Datatype checks in IfcTester are now case insensitive 2023-09-19 23:56:04 +10:00
Andrej730 8320623210 Exposed some MEP operators in BIM Tool UI
https://i.imgur.com/U61QqlQ.png
2023-09-19 17:00:14 +05:00
Andrej730 90c4a2fd41 bim.mep_connect_elements to connect elements by the closest ports
Previously it was looking for exact match. Now operator also adjusts connected ports
2023-09-19 17:00:14 +05:00
Andrej730 4ee66caaf9 override_outliner_delete poll error fix 2023-09-19 16:59:15 +05:00
Andrej730 23251de6f1 info message for refresh_aggregate 2023-09-19 16:59:15 +05:00
Dion Moult 37287bac7e You can now add bSDD properties when assigning bSDD classifications 2023-09-19 20:30:56 +10:00
Vukas Pajic 43a7340f5d Fix case when ids_dict has key but value is None 2023-09-19 12:28:09 +02:00
Dion Moult 2363b5e167 Minor fix 2023-09-19 19:13:21 +10:00
Dion Moult 62bf8c2287 Fix crash where IFCTester read directly from IFC in the UI 2023-09-19 18:17:24 +10:00
Dion Moult a5a958d6e2 Basic integration of bSDD with BlenderBIM Add-on: you can now assign classification references from the bSDD and set the active bSDD domain. 2023-09-19 18:17:24 +10:00
Dion Moult 812d8508f4 Implement classification searching in bSDD library 2023-09-19 18:17:24 +10:00
Andrej730 c40cc3f740 select array parent / all array objects to work without parent guid argument
now it's getting parent guid from the currently active object, not from provided guid argument - so now it's possible to add those operators to quick favorites
2023-09-19 11:48:06 +05:00
Ryan Schultz 56040951f1 Have bim.select_aggregate make the aggregate empty the active object, as well. 2023-09-18 20:21:19 -05:00
Dion Moult 39b1a65dc5 IfcTester now includes percentages per requirement 2023-09-19 09:03:53 +10:00
Sigma Dimensions (Yass) 438f35fe88 purge cost schedules 2023-09-18 20:20:23 +01:00
Dion Moult 9240518066 Accommodate potential manual deletion of EPset drawing. 2023-09-18 23:41:13 +10:00
Dion Moult 27b71a9d07 Fix #3752. Accommodate situations where layouts don't match IFC. 2023-09-18 23:15:05 +10:00
Andrej730 0f1d675bef Associate IFC files with BlenderBIM on Windows
Buttons located in addon preferences - https://i.imgur.com/Unp4P9L.png

Just waiting for this to break somehow...

It's not completely automatic now and it doesn't create assign special icon for IFC files yet.
2023-09-18 18:01:20 +05:00
Andrej730 19345ff538 Remove orphaned IfcPropertyEnumeration
Noticed a couple hundreds of orphaned IfcPropertyEnumeration in my .ifc like below 😁

IFCPROPERTYENUMERATION('Status',(IFCLABEL('NEW'),IFCLABEL('EXISTING'),IFCLABEL('DEMOLISH'),IFCLABEL('TEMPORARY'),IFCLABEL('OTHER'),IFCLABEL('NOTKNOWN'),IFCLABEL('UNSET')),$);
2023-09-18 12:08:16 +05:00
Andrej730 7b28bc9c68 fixed bug creating transition shapes
it was accidentally assigning extrusion vector instead of an offset
2023-09-18 11:30:36 +05:00
Andrej730 d67eae55df Clean up orphaned meshes
- delete_ifc_project
- bim.add_constr_type_instance
- adding transitions and bends
- add profile / slab / wall
2023-09-18 10:58:26 +05:00
Andrej730 8e375dcf73 Save last active context editing doors/windows, solves #3735
previously - https://imgur.com/a/gri6zMk
now - https://imgur.com/a/GIwZP6c
2023-09-18 10:04:45 +05:00
Sigma Dimensions (Yass) a34d0cabfc MSP calendar exceptions are now also imported #3766 2023-09-17 03:10:31 +01:00
Sigma Dimensions (Yass) a668743d10 fix msp .xml import: exception days for a standard working week #3766 2023-09-16 19:29:48 +01:00
Massimo Fabbro b13cbbb244 Partial spatial tool refactor 2023-09-15 22:47:35 +02:00
Andrej730 b6ae5fd344 For parametric doors and windows remove "Edit Profile" button from BIM Tool UI to avoid confusion 2023-09-15 15:55:15 +05:00
Andrej730 1c85034e19 Add starting/saving IFC project to Blender F4 file context menu
https://i.imgur.com/FDvZZwc.png
2023-09-15 15:36:33 +05:00
Andrej730 b0d1823968 MEP bends - fixed bunch of bugs related to adjusting already existing bends types 2023-09-15 15:36:33 +05:00
Dion Moult f0e03c79df Project advanced mode filtering now uses new filter syntax 2023-09-15 11:25:08 +10:00
Andrej730 6109cdf41b Ooops, forgot to remove debug shape creation 2023-09-14 18:19:03 +05:00
Andrej730 ec0873d527 transitions - fixed bug finding compatible fitting
For example, there was a fitting from segment of type A to the segment of type B with start/end transition lengths equal a/b respectively.
And then if you'd try to create a transition from B to A and start/end transition lengths being equal to b/a, previously BBIM wouldn't be able to find that already existing fitting is still compatible.
2023-09-14 18:19:03 +05:00
Andrej730 63223172b4 mep operators - clamp properties below zero 2023-09-14 18:19:03 +05:00
Andrej730 9778253d21 bends - support for zero radius bends 2023-09-14 18:19:03 +05:00
Dion Moult 0140b4ded1 IfcDiff can now visualise across linked IFCs 2023-09-14 22:50:57 +10:00
Dion Moult dca60b83a9 Make IfcDiff more forgiving when invalid geometry occurs. See #3755. 2023-09-14 22:28:03 +10:00
Andrej730 42e683375c Fixed bug using tab editing arbitrary profile
It was assuming we were editing extrusion profile and therefore was giving errors.
2023-09-14 11:06:42 +05:00
Dion Moult 66e07c2f69 Include buildingSMART psets in IfcFM Basic preset 2023-09-14 15:17:52 +10:00
Dion Moult 2b067b9dec Minor fix 2023-09-14 14:27:07 +10:00
Dion Moult c22d7d2f41 More minor fixes to IfcFM basic preset 2023-09-14 14:24:06 +10:00
Dion Moult ea3d489c24 Minor fixes to IfcFM 2023-09-14 12:10:36 +10:00
Andrej730 97683a14ef Revert "Replace currently selected objects with occurences of type"
This reverts commit 58199ef7c9.
2023-09-13 18:44:00 +05:00
Andrej730 d79b912e0e bends - consider profile dimensions searching for compatible fitting
So basically now it won't reuse a bend fitting created for the same profile but with different dimension.
2023-09-13 16:30:20 +05:00
Andrej730 7ec8f8b03e bends - adjusting compatible fitting rotation to match the segments
Demo - https://imgur.com/a/cYdWy9X (note that no bend types created in the process - it's just adjusting the type created for the first two segments).
2023-09-13 16:30:20 +05:00
Andrej730 58199ef7c9 Replace currently selected objects with occurences of type
Added operator to replace currently selected objects with occurences of the chosen type. I kept doing this from the code and thought it could be generally useful.

It's working pretty naive now and just replacing objects with occurences preserving the original transform (location/rotation/scale), nothing else is preserved.

Demo - https://imgur.com/a/qm8a6Ns

PS Hopefully I'm not reinventing the wheel and not missed some other similar operator
2023-09-13 16:30:20 +05:00
Andrej730 d5c46514d3 bends - considering parametric data searching for compatible fitting 2023-09-13 16:30:20 +05:00
Thomas Krijnen f400973557 Correct xsi:schemaLocation 2023-09-13 12:47:33 +02:00
Thomas Krijnen 148d6e7b1b Update IDS.xsd 2023-09-13 10:11:01 +02:00
Dion Moult 74dec650a7 New FM module in BlenderBIM Add-on for interacting with IfcFM. 2023-09-13 17:08:33 +10:00
Dion Moult 5f6e003e4e Implement COBie documents and attributes 2023-09-13 17:08:33 +10:00
Andrej730 d3df22b44b bends - use IfcArcIndex to define bends curves
instead of manually generating polylines of segments
2023-09-12 16:29:33 +05:00
Andrej730 257208d55b bends - support for start and end segments 2023-09-12 16:00:02 +05:00
Andrej730 d8b9b09d14 shapebuilder - replace y extrusion args with shortcut for readibility 2023-09-12 16:00:02 +05:00
Andrej730 6f9e14ceb0 Bends - replace faceset with simple extrusion 2023-09-12 16:00:02 +05:00
Andrej730 d854984dda MEP bends - support for circular profiles
Demo - https://imgur.com/a/XQBOvGz
2023-09-12 16:00:01 +05:00
Dion Moult 2951721886 Don't strip selector query keys to allow for explicit "mistakes" in key names. 2023-09-12 20:45:24 +10:00
Dion Moult 02801b32a6 Minor fix in IfcCSV where strings didn't get auto quoted. 2023-09-12 17:48:23 +10:00
Dion Moult b243e04fd2 New util.system.get_port_element function. 2023-09-12 17:48:23 +10:00
Dion Moult 02902d9a41 Allow optional second arguments to substr formatting. 2023-09-12 17:48:23 +10:00
Dion Moult 5c33034455 Implement COBie assemblies, connections, spares, resources, and jobs. 2023-09-12 17:48:23 +10:00
Thomas Krijnen 7541293a3c Case sensitivity on entity str comparison from cmd line https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/2bf3324a7f 2023-09-11 21:27:54 +02:00
Dion Moult da7d4dac7a Implement COBie systems 2023-09-11 23:24:34 +10:00
Andrej730 507ab8ec11 Fixed top and center alignment in the schedule
Solves #3599

Before - https://i.imgur.com/9s7MxH5.png
After - https://i.imgur.com/ojDj09G.png
Inkscape - https://i.imgur.com/pWF4Ouy.png
2023-09-11 17:30:59 +05:00
Andrej730 e93ff7a6b1 MEP bends - more robust start/end points detection
also support for bends with angles > 90 degrees and some other bugs fixed
2023-09-11 16:28:14 +05:00
Dion Moult 098ae2b69f Implement COBie type and component tables 2023-09-11 18:31:37 +10:00
Dion Moult a58a10e93d Deprecate purge_module_data in favour of newer refresh_ui_data function. 2023-09-10 18:27:05 +10:00
Dion Moult 9be7d951c3 Improve usability of pset template UI by removing save button and using new explicit applicable entity defaults to mitigate possible invalid pset templates. 2023-09-10 17:38:07 +10:00
Dion Moult 6cf482dc63 Minor UI bugfix where pset template files sometimes displayed with truncated filenames 2023-09-10 17:36:07 +10:00
Dion Moult aaa4683462 Fix bug where you couldn't add psets that were inherited. 2023-09-10 17:35:33 +10:00
Dion Moult 0b5535b6d4 Implement COBie zones 2023-09-10 09:04:19 +10:00
Bruno Perdigão cc8f103465 fix rotation from refresh aggregate operator 2023-09-07 21:06:08 -03:00
Carlos Dias 339ab9eeab Merge branch 'IfcOpenShell:v0.7.0' into v0.7.0 2023-09-03 12:33:20 -03:00
Carlos Dias 6c29c53a72 Merge branch 'IfcOpenShell:v0.7.0' into v0.7.0 2023-08-25 08:25:25 -03:00
Carlos Dias 59e11aa804 Merge branch 'IfcOpenShell:v0.7.0' into v0.7.0 2023-08-22 11:14:04 -03:00
Carlos Dias 155a8b79da Merge branch 'IfcOpenShell:v0.7.0' into v0.7.0 2023-08-14 22:10:54 -03:00
Carlos Dias b46ccc9b78 Merge branch 'IfcOpenShell:v0.7.0' into v0.7.0 2023-08-06 11:21:39 -03:00
c4rlosdias 4f1e21dfb0 Add element guId in BCF report 2023-08-05 10:50:27 -03:00
811 changed files with 161822 additions and 16030 deletions
+2 -2
View File
@@ -39,7 +39,7 @@ jobs:
strategy:
fail-fast: false
matrix:
pyver: [py39, py310]
pyver: [py39, py310, py311]
config:
- {
name: "Windows Build",
@@ -62,7 +62,7 @@ jobs:
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
python-version: '3.10'
python-version: '3.11'
- run: echo ${{ env.DATE }}
- name: Get current date
id: date
@@ -1,10 +1,7 @@
name: ci-ifcopenshell-conda-daily
on:
push:
paths:
- .github/workflows/ci-ifcopenshell-conda-daily.yml
- conda/**
workflow_dispatch:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
@@ -15,17 +12,8 @@ on:
- cron: "49 23 * * *" # 11min before utc midnight every day
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- name: Set env
run: echo ok go
test:
name: ${{ matrix.platform.distver }}-${{ matrix.pyver.name }}
needs: activate
name: ${{ matrix.platform.distver }}-${{ matrix.pyver.name }}-${{ matrix.variant }}
runs-on: ${{ matrix.platform.distver }}
defaults:
run:
@@ -34,18 +22,23 @@ jobs:
fail-fast: false
matrix:
pyver: [
{ name: py310, distver: '3.10'},
{ name: py311, distver: '3.11'}
{ name: py311, distver: '3.11'},
{ name: py312, distver: '3.12'}
]
platform: [
{ name: Windows, distver: windows-2022, upload: 'true' },
{ name: Linux, distver: ubuntu-22.04, upload: 'true' },
{ name: macOS, distver: macos-12, upload: 'true' }
]
variant: [
'novtk',
# 'all'
]
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Download MacOSX SDK
if: ${{ matrix.platform.name == 'macOS' }}
run: |
@@ -53,21 +46,22 @@ jobs:
tar xf MacOSX10.13.sdk.tar.xz && \
sudo mv -v MacOSX10.13.sdk /opt/ && \
ls /opt/
- uses: seanmiddleditch/gha-setup-ninja@master
- uses: mamba-org/provision-with-micromamba@main # https://github.com/mamba-org/provision-with-micromamba
- uses: mamba-org/setup-micromamba@v1 # https://github.com/mamba-org/setup-micromamba
with:
channels: conda-forge
channel-priority: strict
environment-file: conda/environment.yml
extra-specs: |
python=${{ matrix.pyver.distver }}
environment-name: build-env
cache-environment: true
condarc: |
channels:
- conda-forge
channel_priority: strict
create-args: >-
python=3.11
anaconda-client
boa
- name: build, test and upload ifcopenshell
if: ${{ matrix.platform.upload == 'true' }}
run: |
conda-build . --python ${{ matrix.pyver.distver }} -c conda-forge --token ${{ secrets.ANACONDA_TOKEN }} --user ifcopenshell
working-directory: ./conda
- name: build & test ifcopenshell
if: ${{ matrix.platform.upload == 'false' }}
run: |
conda-build . --python ${{ matrix.pyver.distver }} -c conda-forge
conda mambabuild . --python ${{ matrix.pyver.distver }} -c conda-forge --variants "{variant: ${{ matrix.variant }}}" --token ${{ secrets.ANACONDA_TOKEN }} --user ifcopenshell
working-directory: ./conda
-99
View File
@@ -1,99 +0,0 @@
name: ci_py_only
on:
push:
paths:
- 'src/**'
- 'test/**'
- 'conda/**'
- 'cmake/**'
- '.github/workflows/ci-py-only.yml'
pull_request:
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell' &&
!contains(github.event.head_commit.message, 'skip ci')
steps:
- run: echo ok go
build:
runs-on: ubuntu-20.04
needs: activate
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Install C++ dependencies
run: |
sudo apt update
sudo apt-get install --no-install-recommends \
git cmake gcc g++ \
libboost-date-time-dev \
libboost-filesystem-dev \
libboost-iostreams-dev \
libboost-program-options-dev \
libboost-regex-dev \
libboost-system-dev \
libboost-thread-dev \
python3-all-dev python3-pip \
swig libpcre3-dev libxml2-dev \
libtbb-dev nlohmann-json3-dev \
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
libhdf5-dev libcgal-dev
- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${GITHUB_WORKFLOW}
- name: Build ifcopenshell
run: |
sudo /usr/sbin/update-ccache-symlinks
mkdir build && cd build
PATH="/usr/lib/ccache:$PATH" cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=/usr \
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 \
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.8 \
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.8.so \
-DCOLLADA_SUPPORT=Off \
"-DSCHEMA_VERSIONS=2x3;4;4x3_add1" \
-DBUILD_CONVERT=Off \
-DGLTF_SUPPORT=On \
-DJSON_INCLUDE_DIR=/usr/include \
-DCGAL_INCLUDE_DIR=/usr/include \
-DGMP_INCLUDE_DIR=/usr/include \
-DMPFR_INCLUDE_DIR=/usr/include \
-DGMP_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
-DMPFR_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
-DHDF5_INCLUDE_DIR=/usr/include/hdf5/serial \
../cmake
sudo make -j $(nproc)
sudo make install
- name: Install Python dependencies
run: |
sudo /usr/bin/python -m pip install -U pip
sudo /usr/bin/python -m pip install xmlschema xsdata numpy lxml
sudo /usr/bin/python -m pip install src/bcf --no-deps
sudo /usr/bin/python -m pip install pytest
sudo /usr/bin/python -m pip install isodate
sudo /usr/bin/python -m pip install lark
sudo /usr/bin/python -m pip install networkx
sudo /usr/bin/python -m pip install tabulate
sudo /usr/bin/python -m pip install python-dateutil
sudo /usr/bin/python -m pip install mathutils
- name: Test
run: |
cd test
sudo /usr/bin/python tests.py
cd ../src/ifcopenshell-python
mv ifcopenshell ifcopenshell-local # Force testing on installed module
make test
+24 -22
View File
@@ -31,12 +31,25 @@ jobs:
- run: echo ok go
build:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
needs: activate
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.11
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install xmlschema xsdata numpy lxml pytest isodate lark networkx tabulate python-dateutil
pip install src/bcf --no-deps
pip install https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
- name: Install C++ dependencies
run: |
sudo apt update
@@ -49,7 +62,6 @@ jobs:
libboost-regex-dev \
libboost-system-dev \
libboost-thread-dev \
python3-all-dev python3-pip \
swig libpcre3-dev libxml2-dev \
libtbb-dev nlohmann-json3-dev \
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
@@ -62,6 +74,9 @@ jobs:
- name: Build ifcopenshell
run: |
echo $Python3_ROOT_DIR
echo ${{ env.pythonLocation }}
mkdir build && cd build
cmake \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
@@ -71,9 +86,9 @@ jobs:
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 \
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.8 \
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.8.so \
-DPYTHON_EXECUTABLE:FILEPATH=${{ env.pythonLocation }}/bin/python \
-DPYTHON_INCLUDE_DIR:PATH=${{ env.pythonLocation }}/include/python3.11 \
-DPYTHON_LIBRARY:FILEPATH=${{ env.pythonLocation }}/lib/libpython3.11.so \
-DCOLLADA_SUPPORT=Off \
"-DSCHEMA_VERSIONS=2x3;4;4x3_add1" \
-DGLTF_SUPPORT=On \
@@ -102,24 +117,11 @@ jobs:
grep 0$ statuses
grep 0$ statuses | wc -l
- name: Install Python dependencies
run: |
sudo /usr/bin/python -m pip install -U pip
sudo /usr/bin/python -m pip install xmlschema xsdata numpy lxml
sudo /usr/bin/python -m pip install src/bcf --no-deps
sudo /usr/bin/python -m pip install pytest
sudo /usr/bin/python -m pip install isodate
sudo /usr/bin/python -m pip install lark
sudo /usr/bin/python -m pip install networkx
sudo /usr/bin/python -m pip install https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
sudo /usr/bin/python -m pip install tabulate
sudo /usr/bin/python -m pip install python-dateutil
sudo /usr/bin/python -m pip install mathutils
- name: Test
- name: Test ifcopenshell-python
run: |
cd test
sudo /usr/bin/python tests.py
python tests.py
cd ../src/ifcopenshell-python
mv ifcopenshell ifcopenshell-local # Force testing on installed module
make test
make test-safe
+6 -12
View File
@@ -7,34 +7,26 @@
# output directories
/cmake/out/
/docs/out/
/src/examples/out/
/src/ifcmax/out/
/src/ifcwrap/out/
/src/qtviewer/out/
/win/BuildDepsCache*.txt
# IfcExpressParser residue
/src/ifcexpressparser/express_parser.py
# General Python residue
__pycache__
*.py.bak
# Visual Studio Code files
.vscode
.vs
# PyCharm files
.idea
#Virtual Env Files
Pipfile
Pipfile.lock
# Docs
/docs/output
/docs/rst_files
/docs/doxygen
/src/ifcblenderexport/docs/_build
/docs/cpp-api/output
# gettext binary translation files
*.mo
@@ -96,6 +88,8 @@ src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py
# apple
.DS_Store
# clangd config
.clangd
# clangd cache
.cache
+4 -1
View File
@@ -10,4 +10,7 @@
url = https://github.com/IfcOpenShell/svgfill
[submodule "src/ifcopenshell-python/test/Sample-BIM-Files"]
path = src/ifcopenshell-python/test/Sample-BIM-Files
url = https://github.com/IfcOpenShell/ids-test-files
url = https://github.com/IfcOpenShell/ids-test-files
[submodule "docs/cpp-api/assets/doxygen-awesome-css"]
path = docs/cpp-api/assets/doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git
+8 -8
View File
@@ -7,13 +7,13 @@ IfcOpenShell
</p>
IfcOpenShell is an open source ([LGPL]) software library for working with Industry Foundation Classes ([IFC]). Complete
parsing support is provided for [IFC2x3 TC1], [IFC4 Add2 TC1], IFC4x1, IFC4x2, and IFC4x3. Extensive geometric support
parsing support is provided for [IFC2x3 TC1], [IFC4 Add2 TC1], IFC4x1, IFC4x2, and [IFC4x3 Add2]. Extensive geometric support
is implemented for the IFC releases [IFC2x3 TC1] and [IFC4 Add2 TC1]. Extending with support for arbitrary IFC schemas
is possible at compile-time when using C++ and at run-time when using Python.
In addition to a C++ and Python API, IfcOpenShell comes with an ecosystem of tools, notably including IfcConvert (an application to convert IFC models to
other formats), the BlenderBIM Add-on (an add-on to Blender providing a graphical IFC authoring platform), and many
other libraries, CLI apps, and more. Support is also provided for auxiliary standards such as BCF and IDS.
In addition to a C++ and Python API, IfcOpenShell comes with an ecosystem of tools, notably including IfcConvert (an application
to convert IFC models to other formats), the BlenderBIM Add-on (an add-on to Blender providing a graphical IFC authoring platform),
and many other libraries, CLI apps, and more. Support is also provided for auxiliary standards such as BCF and IDS.
For more information, see:
@@ -32,8 +32,8 @@ For more information, see:
| Anaconda Daily Build | [![Anaconda-Server Badge](https://img.shields.io/conda/vn/ifcopenshell/ifcopenshell)](https://anaconda.org/ifcopenshell/ifcopenshell) |
| Anaconda v0.7.0 Stable | [![Anaconda-Server Badge](https://img.shields.io/conda/vn/conda-forge/ifcopenshell)](https://anaconda.org/conda-forge/ifcopenshell) |
| PyPi Daily Build | [![PyPi Badge](https://img.shields.io/pypi/v/ifcopenshell)](https://pypi.org/project/ifcopenshell/) |
| ArchLinux AUR Package Stable | [![AUR Badge](https://img.shields.io/aur/version/ifcopenshell)](https://aur.archlinux.org/packages/ifcopenshell) |
| ArchLinux AUR Package git | [![AUR Badge](https://img.shields.io/aur/version/ifcopenshell-git)](https://aur.archlinux.org/packages/ifcopenshell-git) |
| ArchLinux AUR Package Stable | [![AUR Badge](https://img.shields.io/aur/version/ifcopenshell)](https://aur.archlinux.org/packages/ifcopenshell) |
| ArchLinux AUR Package git | [![AUR Badge](https://img.shields.io/aur/version/ifcopenshell-git)](https://aur.archlinux.org/packages/ifcopenshell-git) |
| BlenderBIM Add-on Chocolatey (under moderation) | [![Chocolatey Badge](https://img.shields.io/chocolatey/v/blenderbim-nightly)](https://community.chocolatey.org/packages/blenderbim-nightly/) |
| Sponsor development on OpenCollective | [![Financial Contributors](https://opencollective.com/opensourcebim/tiers/badge.svg)](https://opencollective.com/opensourcebim/) |
| Docker hub | [![Docker Pulls](https://img.shields.io/docker/pulls/aecgeeks/ifcopenshell)](https://hub.docker.com/r/aecgeeks/ifcopenshell) |
@@ -44,7 +44,7 @@ Contents
Those marked with an asterisk are part of IfcOpenShell.
| Name | Description | License |
| ------------------------- | ----------------------------------------------------------------------| ------------------- |
| ------------------------- | --------------------------------------------------------------------- | ------------------- |
| bcf | Library to read and write BCF-XML and query OpenCDE BCF-API modules | LGPL-3.0-or-later |
| blenderbim | Add-on to Blender providing a graphical native IFC authoring platform | GPL-3.0-or-later |
| bsdd | Library to query the bSDD API | LGPL-3.0-or-later |
@@ -55,7 +55,6 @@ Those marked with an asterisk are part of IfcOpenShell.
| ifcblender | Historic Blender IFC import add-on | LGPL-3.0-or-later\* |
| ifccityjson | Convert CityJSON to IFC | LGPL-3.0-or-later |
| ifcclash | Clash detection library and CLI app | LGPL-3.0-or-later |
| ifccobie | Extract IFC data for COBie handover requirements | LGPL-3.0-or-later |
| ifcconvert | CLI app to convert IFC to many other formats | LGPL-3.0-or-later\* |
| ifccsv | Library and CLI app to export and import schedules from IFC | LGPL-3.0-or-later |
| ifcdiff | Compare changes between IFC models | LGPL-3.0-or-later |
@@ -78,6 +77,7 @@ Those marked with an asterisk are part of IfcOpenShell.
[IFC]: https://technical.buildingsmart.org/standards/ifc/ "IFC"
[IFC2x3 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/TC1/HTML/ "IFC2x3 TC1"
[IFC4 Add2 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC4/ADD2_TC1/HTML/ "IFC4 Add2 TC1"
[IFC4x3 Add2]: https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/ "IFC4x3 Add2"
[Visual Studio]: https://www.visualstudio.com/ "Visual Studio"
[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools "Visual C++ Build Tools"
[MSYS2]: https://msys2.github.io/ "MSYS2"
+1 -1
View File
@@ -29,7 +29,7 @@ URL_CHOCO_PACKAGE = "https://community.chocolatey.org/packages/blender"
URL_BLENDER_CMAKE = "https://raw.githubusercontent.com/blender/blender/{}/build_files/cmake/Modules/FindPythonLibsUnix.cmake"
RE_BLENDER_VERSION_MIN_MAJ = r"Latest Version.+<span>Blender (\d+\.\d+)\..+</span>"
RE_BLENDER_VERSION_MIN_MAJ_PAT = r"Latest Version.+<span>Blender (\d+\.\d+\.\d+)</span>"
RE_BLENDER_PYTHON_VERSION_MAJ_MIN = r"SET\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
RE_BLENDER_PYTHON_VERSION_MAJ_MIN = r"(?:set|SET)\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
if sys.argv[1] == "--do_choco_release?":
+40 -18
View File
@@ -58,6 +58,7 @@ option(BUILD_PACKAGE "" OFF)
option(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
option(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF)
option(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
option(WITH_PROJ "Enable output of Earth-Centered Earth-Fixed glTF output using the PROJ library" OFF)
option(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
option(USD_SUPPORT "Build IfcConvert with USD support (requires pixar's USD library)." OFF)
@@ -438,9 +439,13 @@ if(BUILD_IFCGEOM)
if(WASM_BUILD)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
else()
# OPENCASCADE_LIBRARIES repeated N times below in order to fix cyclic dependencies - use --start-group ... --end-group instead?
# OPENCASCADE_LIBRARIES repeated N times below in order to fix cyclic dependencies
# tfk: --start-group ... --end-group didn't work on the apple linker when last tested
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
if(APPLE)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
else()
set(OPENCASCADE_LIBRARIES -Wl,--start-group ${OPENCASCADE_LIBRARIES} -Wl,--end-group ${CMAKE_THREAD_LIBS_INIT})
endif()
endif()
if (NOT APPLE AND NOT WIN32)
@@ -580,23 +585,31 @@ if(HDF5_SUPPORT)
if(WIN32)
# Windows
set(zlib_post zlib)
set(lib_ext lib)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# macOS
set(zlib_post libz)
set(lib_ext dylib)
set(HDF5_LIBRARIES)
find_package(HDF5 COMPONENTS CXX)
if (HDF5_FOUND)
set(HDF5_LIBRARIES ${HDF5_CXX_LIBRARIES})
endif()
list(APPEND HDF5_LIBRARIES
"${HDF5_LIBRARY_DIR}/zlib.lib"
)
else()
# linux
set(zlib_post libz)
set(lib_ext so)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# macOS
set(zlib_post libz)
set(lib_ext dylib)
else()
# linux
set(zlib_post libz)
set(lib_ext so)
endif()
set(HDF5_LIBRARIES
"${HDF5_LIBRARY_DIR}/libhdf5_cpp.${lib_ext}"
"${HDF5_LIBRARY_DIR}/libhdf5.${lib_ext}"
"${HDF5_LIBRARY_DIR}/${zlib_post}.${lib_ext}"
)
set(HDF5_LIBRARIES
"${HDF5_LIBRARY_DIR}/libhdf5_cpp.${lib_ext}"
"${HDF5_LIBRARY_DIR}/libhdf5.${lib_ext}"
"${HDF5_LIBRARY_DIR}/${zlib_post}.${lib_ext}"
)
endif()
endif()
endif()
@@ -738,7 +751,7 @@ if(NOT SCHEMA_VERSIONS)
# super arbitrarily try to keep size down at least a little bit
set(SCHEMA_VERSIONS "2x3" "4")
else()
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3_rc1" "4x3_rc2" "4x3_rc3" "4x3_rc4" "4x3" "4x3_tc1" "4x3_add1")
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3_rc1" "4x3_rc2" "4x3_rc3" "4x3_rc4" "4x3" "4x3_tc1" "4x3_add1" "4x3_add2")
endif()
endif()
@@ -934,6 +947,15 @@ if(BUILD_CONVERT OR BUILD_IFCPYTHON)
add_library(Serializers ${SERIALIZERS_FILES})
set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS" VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
if (WITH_PROJ)
target_compile_definitions(Serializers PRIVATE "WITH_PROJ")
if (PROJ_STATIC)
target_compile_definitions(Serializers PRIVATE "PROJ_DLL=")
endif()
target_include_directories(Serializers PRIVATE ${PROJ_INCLUDE_DIR} ${SQLITE_INCLUDE_DIR})
target_link_libraries(Serializers ${PROJ_LIBRARIES})
endif()
target_link_libraries(Serializers ${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES})
endif(BUILD_CONVERT OR BUILD_IFCPYTHON)
-8
View File
@@ -1,8 +0,0 @@
compile:
conda activate conda-build && conda-build -c conda-forge . --keep-old-work --python 3.10.5
debug:
conda activate conda-build && conda-debug -c conda-forge . --python 3.10.4
env:
conda env update --f environment.yml --prune
+5 -1
View File
@@ -1,2 +1,6 @@
CONDA_BUILD_SYSROOT:
- /opt/MacOSX10.13.sdk # [osx]
- /opt/MacOSX10.13.sdk # [osx]
variant:
- novtk
- all
-13
View File
@@ -1,13 +0,0 @@
name: conda-build
channels:
- conda-forge
dependencies:
- conda-build
- conda-verify
- anaconda-client
- ninja
- doxygen
- ripgrep
- pip
- pip:
- lief==0.13
+12 -7
View File
@@ -1,6 +1,10 @@
{% set name = "ifcopenshell" %}
{% set version = "0.7.0" %}
{% set build = 1 %}
# Higher number -> Always prioritize "novtk" variant over "all" variant
{% set build = build + 200 %} # [variant == "novtk"]
{% set build = build + 100 %} # [variant == "all"]
package:
name: {{ name }}
@@ -10,8 +14,9 @@ source:
path: ..
build:
string: py{{ CONDA_PY }}_{{ variant }}_h{{ PKG_HASH }}_{{ build }}
binary_relocation: false [osx]
number: 1
number: {{ build }}
requirements:
build:
@@ -19,12 +24,12 @@ requirements:
- {{ compiler('cxx') }}
- ninja >=1.10.2
- cmake
- swig >=4.0.2
- swig 4.1.1
host:
- python
- boost-cpp
- occt ==7.7.0
- occt 7.7.2 *{{ variant }}*
- libxml2
- cgal-cpp
- hdf5
@@ -36,11 +41,11 @@ requirements:
run:
- python
- {{ pin_compatible('occt', max_pin='x.x.x') }}
- occt 7.7.2 *{{ variant }}*
- {{ pin_compatible('cgal-cpp', max_pin='x.x.x') }}
- {{ pin_compatible('boost-cpp', max_pin='x.x.x') }}
- {{ pin_compatible('hdf5', max_pin='x.x.x') }}
- libxml2
- hdf5
- mpfr
- gmp # [unix]
- mpir # [win]
@@ -52,12 +57,12 @@ test:
- ifcopenshell
about:
home: http://ifcopenshell.org
home: https://ifcopenshell.org
license: LGPL-3.0-or-later
license_file: COPYING
summary: 'IfcOpenShell is a library to support the IFC file format'
description: |
IfcOpenShell is an open source (LGPL) software library for
working with the Industry Foundation Classes (IFC) file format.
doc_url: http://ifcopenshell.org/
doc_url: https://ifcopenshell.org/
dev_url: https://github.com/IfcOpenShell/IfcOpenShell
-11
View File
@@ -1,11 +0,0 @@
#Look for an executable called sphinx-build
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build
DOC "Path to sphinx-build executable")
include(FindPackageHandleStandardArgs)
#Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args(Sphinx
"Failed to find sphinx-build executable"
SPHINX_EXECUTABLE)
-11
View File
@@ -1,11 +0,0 @@
#Look for an executable called sphinx-build
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build
DOC "Path to sphinx-build executable")
include(FindPackageHandleStandardArgs)
#Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args(Sphinx
"Failed to find sphinx-build executable"
SPHINX_EXECUTABLE)
File diff suppressed because it is too large Load Diff
+33
View File
@@ -0,0 +1,33 @@
# IfcOpenShell C++ API documentation
This folder contains the setup to build the IfcOpenShell C++ API documentation from the source code.
## Generating the documentation
> Prerequisites:
>
> Make sure to have [Doxygen](https://www.doxygen.nl) and [Graphviz](https://graphviz.org) installed into your `$PATH` variable.
>
> The documentation also use the [doxygen-awesome](https://jothepro.github.io/doxygen-awesome-css) theme as a git submodule.
Build with the command (from within the `/docs/cpp-api` folder):
```shell
$ doxygen
```
To include the current git commit hash into the build documentation, use the following command:
```shell
$ PROJECT_NUMBER=$(git rev-parse --short HEAD) doxygen
```
This will extract the current commit hash in short version and sets the propper ENV variable used by doxygen.
The generation of the documentation might take a while depending on your systems hardware, as it is configured to generate the Class graphs using .
The resulting documentation is located unter `/cpp-api/output/html` and can be directly accessed with your browser:
```shell
$ open ./output/html/index.html
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

-240
View File
@@ -1,240 +0,0 @@
APPLY_DEFAULT_MATERIALS
-----------------------
Given the command invocation:
Duplex_A_20110907_optimized.ifc d.dae -yv --include attribute GlobalId 3bXiCStxP6Fgxdej$yc50U
You will find log messages along the lines of
[Warning] {3bXiCStxP6Fgxdej$yc50U} No material and surface styles for:
#333=IfcCovering('3bXiCStxP6Fgxdej$yc50U',#1,'Compound Ceiling:Gypsum Board:187483',$,'Compound Ceiling:Gypsum Board',#17840,#17052,'187483',.CEILING.)
This means that there is no IfcStyledItem associated to the representation items and that the element does not have an IfcMaterial association with IfcMaterialRepresentation from which we can derive a style (colour) for the element.
The interactive session below shows how with this setting enabled you will get a default generated material from the IFC element entity type and material indices of 0 pointing to that. With this setting disabled the material index would be -1 to indicate a missing style. Note that there is one material index for every triangle in the list of `shp.geometry.faces`.
>>> import ifcopenshell, ifcopenshell.geom
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
>>> s = ifcopenshell.geom.settings()
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
>>>
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> shp.geometry.material_ids
(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
>>> [(m.name, m.diffuse) for m in shp.geometry.materials]
[]
>>>
>>> s.set(s.APPLY_DEFAULT_MATERIALS, True)
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> shp.geometry.material_ids
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
>>> [(m.name, m.diffuse) for m in shp.geometry.materials]
[('IfcCovering', (0.7, 0.7, 0.7))]
This is enabled by default for the IfcConvert serializers as they will not gracefully handle -1 material indices and allows users to quickly assign colours based on entity types in their modelling applications.
APPLY_LAYERSETS
---------------
This setting is available in IfcConvert as `--enable-layerset-slicing`.
For IfcWall and IfcSlab elements, takes the associated IfcMaterialLayerSet and builds a set of surfaces to segment the building element geometry.
Note that enabling this settings is computationally intensive as it involves 3D Boolean operations.
Duplex_A_20110907_optimized.ifc d1.dae -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d1.dae](images/settings-1.png)
Duplex_A_20110907_optimized.ifc d2.dae --enable-layerset-slicing -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d2.dae](images/settings-2.png)
BUILDING_LOCAL_PLACEMENT
------------------------
This setting is available in IfcConvert using `--building-local-placement`.
In the typical IfcSite > IfcBuilding > IfcBuildingStorey > ... hierarchy of elements, don't incorporate the ObjectPlacement of the IfcBuilding and above in the placement of elements in the output. This is useful when there is a large offset in this placement that reduces precision in further processing.
CONVERT_BACK_UNITS
------------------
This setting is available in IfcConvert using `--convert-back-units`.
Internally IfcOpenShell uses meters as the global length unit to do calculations. This setting restores the coordinate positions after conversion by multiplying the factor of the IfcUnit with UnitType=LENGTHUNIT into the output geometry coordinate values.
DISABLE_OPENING_SUBTRACTIONS
----------------------------
This setting is available in IfcConvert using `--disable-opening-subtraction`.
As in most viewer applications, IfcOpeningElement geometry is subtracted from their host elements. This setting disables this behavior.
Duplex_A_20110907_optimized.ifc d1.dae -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d1.dae](images/settings-1.png)
Duplex_A_20110907_optimized.ifc d3.dae --disable-opening-subtraction -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d3.dae](images/settings-3.png)
Note that disabling this settings will reduce processing time and improve robustness as it involves 3D Boolean operations.
DISABLE_TRIANGULATION
---------------------
To be used in conjunction with `USE_BREP_DATA`. Do not apply the triangulation and - when `USE_BREP_DATA` is set - return a OpenCASCADE serialized TopoDS_Shape from `create_shape()` and `iterator`.
>>> import ifcopenshell, ifcopenshell.geom
>>> s = ifcopenshell.geom.settings()
>>> s.set(s.DISABLE_TRIANGULATION, True)
>>> s.set(s.USE_BREP_DATA, True)
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> print(shp.geometry.brep_data)
CASCADE Topology V1, (c) Matra-Datavision
Locations 0
Curve2ds 0
Curves 12
1 4.6750000000000034 -8.0749999999999904 2.657 -2.0455514041918775e-15 -1 0
1 4.6750000000000034 -8.0749999999999904 2.657 1 -3.435893306383461e-15 0
1 6.2260000000000044 -8.0749999999999957 2.657 -2.0455514041918724e-15 -1 0
1 6.226 -10.246000000000031 2.657 -1 6.8717866127669219e-15 0
...
EDGE_ARROWS
-----------
When `INCLUDE_CURVES` is true and geometric elements include curves (such as the wall axis), add arrow heads to the edges to indicate direction of the curve.
Duplex_A_20110907_optimized.ifc d4.dae --model --plan --edge-arrows -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d4.dae](images/settings-4.png)
EXCLUDE_SOLIDS_AND_SURFACES
---------------------------
Exclude faces, shells and solids from geometrical output. Implied when using `--plan` without `--model` in IfcConvert.
FASTER_BOOLEANS
---------------
NOTE: Only applicable when using OCCT 6.9 and earlier.
This setting is available in IfcConvert using `--merge-boolean-operands`.
Fuse the collection of all boolean operands into a single union before applying the boolean subtraction, as opposed to doing individual subtractions. This likely improves performance. From OCCT 7.0 onwards the boolean operations with multiple arguments is used.
GENERATE_UVS
------------
This setting is available in IfcConvert using `--generate-uvs`.
Applies a box projection on the generated geometry for the element to obtain UV coordinates. This is purely generated, it does not involve texture coordinates stored in the IFC model.
Duplex_A_20110907_optimized.ifc d5.dae --generate-uvs -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d5.dae with a UV grid applied in Blender](images/settings-5.png)
INCLUDE_CURVES
--------------
This setting is available in IfcConvert using `--plan`.
Include edge and wire geometries in the geometric output.
LAYERSET_FIRST
--------------
This setting is available in IfcConvert using `--layerset-first`.
When not using APPLY_LAYERSETS, take the first material layer from the set to use as the material for the overall element.
NO_NORMALS
----------
This setting is available in IfcConvert using `--no-normals`.
Do not emit normals on geometric output
SEARCH_FLOOR
------------
Note: Only applicable to Collada .DAE output when used from IfcConvert.
This setting is available in IfcConvert using `--use-element-hierarchy`.
Include the spatial hierarchy in the elements.
SEW_SHELLS
----------
This setting is available in IfcConvert using `--orient-shells`.
Re-orient or sew connected face sets to have a consistent outwards orientation.
SITE_LOCAL_PLACEMENT
--------------------
This setting is available in IfcConvert using `--site-local-placement`.
See `BUILDING_LOCAL_PLACEMENT`, but exclude also the ObjectPlacement of the IfcSite.
USE_BREP_DATA
-------------
See `DISABLE_TRIANGULATION`.
USE_PYTHON_OPENCASCADE
----------------------
Note: Only available when an import of `OCC.Core.BRepTools` or `OCC.BRepTools` succeeds.
This implies `USE_WORLD_COORDS` `USE_BREP_DATA` and `DISABLE_TRIANGULATION`. The serialized TopoDS_Shape of `USE_BREP_DATA` is deserialized by Python OpenCASCADE.
USE_WORLD_COORDS
----------------
Apply the ObjectPlacement of the building elements to the geometric output. This is implied when using the Wavefront .OBJ output in IfcConvert. Note that this also eliminates the possibility for geometric elements to point to the same interpreted geometry result.
VALIDATE_QUANTITIES
-------------------
This setting is available in IfcConvert using `--validate`.
Running IfcConvert with `--validate` will set a non-zero exit code when ever a log message with severity equal or greater than ERROR has been emitted.
Currently for internal use only. For every building element geometry converted, looks for an associated quantity set where the OwnerHistory's organization name is IfcOpenShell. And looks for the quantities "Total Surface Area", "Volume", "Shape Validation Properties.Surface Genus" and validates these according to the interpreted geometry definition. Emit Logger::Error when calculated values are outside of the tolerance range for the value stored in the model.
WELD_VERTICES
-------------
Note: In Python, this setting is *on* by default.
Note: This setting only affects triangulated output.
This setting is available in IfcConvert using `--weld-vertices`.
Discards normals and joins vertices solely based on position. This is useful when output is to be modified in a modeling application.
>>> import ifcopenshell, ifcopenshell.geom
>>> s = ifcopenshell.geom.settings()
>>> s.set(s.WELD_VERTICES, False)
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> shp.geometry.verts
(4.675000000000003, -8.07499999999999, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6, 4.674999999999999, -10.24600000000002, 2.657, 4.674999999999999, -10.24600000000002, 2.6, 4.675000000000003, -8.07499999999999, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 6.226, -10.24600000000003, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226, -10.24600000000003, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6, 4.675000000000003, -8.07499999999999, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 6.226000000000004, -8.074999999999996, 2.657, 6.226000000000004, -8.074999999999996, 2.6)
>>> shp.geometry.normals
(3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0)
>>>
>>> s.set(s.WELD_VERTICES, True)
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> shp.geometry.verts
(4.675000000000003, -8.07499999999999, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6)
>>> shp.geometry.normals
()
+4 -3
View File
@@ -76,7 +76,7 @@ PROJECT_NAME = "IfcOpenShell"
USE_CURRENT_PYTHON_VERSION = os.getenv("USE_CURRENT_PYTHON_VERSION")
ADD_COMMIT_SHA = os.getenv("ADD_COMMIT_SHA")
PYTHON_VERSIONS = ["3.6.14", "3.7.13", "3.8.13", "3.9.11", "3.10.3", "3.11.0"]
PYTHON_VERSIONS = ["3.6.14", "3.7.13", "3.8.13", "3.9.11", "3.10.3", "3.11.7", "3.12.1"]
JSON_VERSION = "v3.6.1"
OCE_VERSION = "0.18.3"
OCCT_VERSION = "7.5.3"
@@ -892,8 +892,9 @@ if "IfcOpenShell-Python" in targets:
module_dir = os.path.dirname(run([python_executable, "-c", "import inspect, ifcopenshell; print(inspect.getfile(ifcopenshell))"]))
if platform.system() != "Darwin":
# TODO: This symbol name depends on the Python version?
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
if BUILD_CFG == "Release":
# TODO: This symbol name depends on the Python version?
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
return module_dir
+3 -82
View File
@@ -1,84 +1,5 @@
# bcf
A simple Python implementation of BCF.
Manipulation of BCF-XML is available via `bcfxml.py` and manipulation of BCF-API
is available via `bcfapi.py`.
It tries to support BCF-XML version 2.1 and 3.0, and BCF-API 3.0.
## bcfxml
The `bcfxml.load` function lets you read a BCF-XML file.
It takes care of using the right version based on the "bcf.version" file contained in the BCF package.
The BCF files are extracted and parsed on-demand, and edits are stored in memory until you call the `save` method.
```python
from bcf.bcfxml import load
# Load a project
with load("/path/to/file.bcf") as bcfxml:
project = bcfxml.project
print(project.name)
# To edit a project, just modify the object directly
bcfxml.project.name = "New name"
# Get a dictionary of topics
topics = bcfxml.topics
for topic_guid, topic_handler in bcfxml.topics.items():
topic = topic_handler.topic
print("Topic guid is", topic.guid)
print("Topic title is", topic.title)
# Fetch extra data about a topic
header = topic_handler.header
comments = topic_handler.comments
viewpoints = topic_handler.viewpoints
for comment in comments:
print(comment.guid)
print(comment.comment)
print(comment.author)
# Get a particular topic
topic = bcfxml.get_topic(guid)
# Modify a topic
topic.title = "New title"
bcfxml.save()
```
## bcfapi
The `bcfapi` module lets you interact with the BCF-API standard.
```python
from bcf.v3.bcfapi import FoundationClient, BcfClient
foundation_client = FoundationClient("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET", "OPENCDE_BASEURL")
auth_methods = foundation_client.get_auth_methods()
# Our library currently only implements the authorization_code flow
if "authorization_code" in auth_methods:
foundation_client.login()
bcf_client = BcfClient(foundation_client)
versions = foundation_client.get_versions()
for version in versions:
if "3.0" in versions:
if version["api_id"] == "bcf" and version["version_id"] == "3.0":
bcf_client.set_version(version)
data = bcf_client.get_projects()
print(data)
project_id = data[0]["project_id"]
print(project_id)
data = bcf_client.get_project(project_id)
print(data)
data = bcf_client.get_extensions(project_id)
print(data)
```
A simple Python implementation of the BCF standard. Manipulation of BCF-XML is
available via `bcfxml.py` and manipulation of BCF-API is available via
`bcfapi.py`.
+92 -58
View File
@@ -50,24 +50,31 @@ PYLIBDIR:=python3.10
PYNUMBER:=310
PYPI_VERSION:=3.10
endif
ifeq ($(PYVERSION), py311)
PYLIBDIR:=python3.11
PYNUMBER:=311
PYPI_VERSION:=3.11
endif
ifeq ($(PLATFORM), linux)
PYPI_PLATFORM:=--platform manylinux_2_17_x86_64
LXML_ARCH:=manylinux_2_28_x86_64
SHAPELY_ARCH:=manylinux_2_17_x86_64.manylinux2014_x86_64
PILLOW_ARCH:=manylinux_2_28_x86_64
ifeq ($(PYVERSION), py39)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/linux-64/hpp-fcl-2.3.4-py39h40a70d0_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/linux-64/eigenpy-3.1.0-py39hdfdd6bb_0.conda
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/linux-64/hpp-fcl-2.4.0-py39h359ec1e_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/linux-64/eigenpy-3.2.0-py39hb1babde_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py39h7c9e3ff_4.tar.bz2
LXML_URL:=https://files.pythonhosted.org/packages/19/d9/a69c6aff5673554df48120565a14a50eaa41d29ae03b02faa0b023666318/lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl
SHAPELY_URL:=https://files.pythonhosted.org/packages/2d/f2/8ec281d357e8bb7d08dc8d727f0e4c8ef3dae7d3fa75c69c8e452bb82d50/shapely-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
PILLOW_URL:=https://files.pythonhosted.org/packages/01/61/3ff85fb4bb596ce3d223c8fcf93c8df5c12bc8899dfb4fb3cb1c5b20dd5f/Pillow-9.2.0-cp39-cp39-manylinux_2_28_x86_64.whl
endif
ifeq ($(PYVERSION), py310)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/linux-64/hpp-fcl-2.3.4-py310h995690b_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/linux-64/eigenpy-3.1.0-py310hf02b7e0_0.conda
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/linux-64/hpp-fcl-2.4.0-py310hd002f03_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/linux-64/eigenpy-3.2.0-py310hcfe0b05_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py310hc4a4660_4.tar.bz2
LXML_URL:=https://files.pythonhosted.org/packages/25/1e/19b46d8e8881fe0df2e20945d51919eeb1817836d62a90efa8506530e45c/lxml-4.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl
SHAPELY_URL:=https://files.pythonhosted.org/packages/a8/a5/403728b5614b28083f6424dfdefec5fcf58068495fb03bb08532671c642f/shapely-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
PILLOW_URL:=https://files.pythonhosted.org/packages/f6/51/320986ebd6d46a0e95c2240468ced73153b691ce07617078bcdf30c609ec/Pillow-9.2.0-cp310-cp310-manylinux_2_28_x86_64.whl
endif
ifeq ($(PYVERSION), py311)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/linux-64/hpp-fcl-2.4.0-py311h04f086a_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/linux-64/eigenpy-3.2.0-py311h995a085_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py311h59ea3da_3.tar.bz2
endif
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/linux-64/assimp-5.0.1-hedfc422_6.tar.bz2
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/linux-64/qhull-2020.2-h4bd325d_2.tar.bz2
@@ -78,21 +85,25 @@ endif
ifeq ($(PLATFORM), macos)
PYPI_PLATFORM:=--platform macosx_10_9_x86_64
SHAPELY_ARCH:=macosx_10_9_x86_64
PILLOW_ARCH:=macosx_10_10_x86_64
ifeq ($(PYVERSION), py39)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-64/hpp-fcl-2.3.4-py39hd85b194_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-64/eigenpy-3.1.0-py39hc4d6e28_0.conda
LXML_ARCH:=macosx_11_0_x86_64
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-64/hpp-fcl-2.4.0-py39h26350b9_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-64/eigenpy-3.2.0-py39h3323527_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py39h953a6b8_4.tar.bz2
LXML_URL:=https://files.pythonhosted.org/packages/b8/74/a71f7ad72e8db54ce899efab84507b801660750cbbfa6a39e6717557d36a/lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl
SHAPELY_URL:=https://files.pythonhosted.org/packages/36/a4/7e542a209f862f967d7cb8e939eff155f4294a27d17e16441fb8bdd51a2c/shapely-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl
PILLOW_URL:=https://files.pythonhosted.org/packages/88/7a/ddfe28b485b623361457d4783007c1f9ba83a87f93e7fec32f64793efb6c/Pillow-9.2.0-cp39-cp39-macosx_10_10_x86_64.whl
endif
ifeq ($(PYVERSION), py310)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-64/hpp-fcl-2.3.4-py310h1db6f5f_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-64/eigenpy-3.1.0-py310h43da829_0.conda
LXML_ARCH:=macosx_11_0_x86_64
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-64/hpp-fcl-2.4.0-py310ha216469_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-64/eigenpy-3.2.0-py310h33a8c9b_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py310h3e792ce_4.tar.bz2
LXML_URL:=https://files.pythonhosted.org/packages/a1/44/17b7dac7a18807d30e2fe10c3328c152808f5464565e230bfd0e77f178c6/lxml-4.8.0-cp310-cp310-macosx_10_15_x86_64.whl
SHAPELY_URL:=https://files.pythonhosted.org/packages/1f/2a/dc3353c2431cf53e8d04bb8fba27e584410ca3435c9c85f76d71bf0c0e80/shapely-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl
PILLOW_URL:=https://files.pythonhosted.org/packages/d8/60/b13c00d403f34110e96c1b5c0afa73ce461efe3fe960c3a7e3e7fe190d82/Pillow-9.2.0-cp310-cp310-macosx_10_10_x86_64.whl
endif
ifeq ($(PYVERSION), py311)
LXML_ARCH:=macosx_11_0_universal2
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-64/hpp-fcl-2.4.0-py311hebdd1a2_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-64/eigenpy-3.2.0-py311h62e90b6_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py311h349b758_4.tar.bz2
endif
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/osx-64/assimp-5.0.1-h1224e73_6.tar.bz2
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-64/qhull-2020.2-h940c156_2.tar.bz2
@@ -103,21 +114,23 @@ endif
ifeq ($(PLATFORM), macosm1)
PYPI_PLATFORM:=--platform macosx_11_0_arm64
LXML_ARCH:=macosx_11_0_universal2
SHAPELY_ARCH:=macosx_11_0_arm64
PILLOW_ARCH:=macosx_11_0_arm64
ifeq ($(PYVERSION), py39)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-arm64/hpp-fcl-2.3.4-py39hc34188a_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-arm64/eigenpy-3.1.0-py39h13cfc01_0.conda
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-arm64/hpp-fcl-2.4.0-py39h82b2ff2_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-arm64/eigenpy-3.2.0-py39h3a9e884_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py39h99de9ae_4.tar.bz2
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py39h9eb174b_0.tar.bz2
SHAPELY_URL:=https://files.pythonhosted.org/packages/ea/aa/45fbd031edf3149cb767d8b9f9db45d5faf0324d743c6b8fb0298cc022d0/shapely-2.0.1-cp39-cp39-macosx_11_0_arm64.whl
PILLOW_URL:=https://files.pythonhosted.org/packages/aa/bc/21097cd891dd2fa02f2b3d767e02e883e026482e59d29975d1bc30024aa3/Pillow-9.2.0-cp39-cp39-macosx_11_0_arm64.whl
endif
ifeq ($(PYVERSION), py310)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-arm64/hpp-fcl-2.3.4-py310h46fc4cd_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-arm64/eigenpy-3.1.0-py310ha2643af_0.conda
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-arm64/hpp-fcl-2.4.0-py310hdb6c3eb_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-arm64/eigenpy-3.2.0-py310h96e9823_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py310h629746b_4.tar.bz2
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py310h02f21da_0.tar.bz2
SHAPELY_URL:=https://files.pythonhosted.org/packages/ec/41/d59208743e737184e1b403e95a937aebb022b8459e99efbcd5208fc8be46/shapely-2.0.1-cp310-cp310-macosx_11_0_arm64.whl
PILLOW_URL:=https://files.pythonhosted.org/packages/0c/5f/117b653cad585f3aedfe0de996c292e67d4b020ed77f652e5a6c8c24f908/Pillow-9.2.0-cp310-cp310-macosx_11_0_arm64.whl
endif
ifeq ($(PYVERSION), py311)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-arm64/hpp-fcl-2.4.0-py311hc0c29b9_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-arm64/eigenpy-3.2.0-py311h24fa84d_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py311h5c64717_4.tar.bz2
endif
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/osx-arm64/assimp-5.0.1-h0f81e16_7.tar.bz2
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-arm64/qhull-2020.2-hc021e02_2.tar.bz2
@@ -128,21 +141,23 @@ endif
ifeq ($(PLATFORM), win)
PYPI_PLATFORM:=--platform win_amd64
LXML_ARCH:=win_amd64
SHAPELY_ARCH:=win_amd64
PILLOW_ARCH:=win_amd64
ifeq ($(PYVERSION), py39)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/win-64/hpp-fcl-2.3.4-py39h39b25cb_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/win-64/eigenpy-3.1.0-py39hb6c915b_0.conda
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/win-64/hpp-fcl-2.4.0-py39hf3ebc58_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/win-64/eigenpy-3.2.0-py39ha1f6a47_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/win-64/boost-1.78.0-py39hea4d8d1_4.tar.bz2
LXML_URL:=https://files.pythonhosted.org/packages/72/d4/426ecb8849c47c3e370c87aa0ac05d85768df917ffea27fcd6686a5e6495/lxml-4.6.3-cp39-cp39-win_amd64.whl
SHAPELY_URL:=https://files.pythonhosted.org/packages/a7/ae/eab645c4075093584b7a65ab71cb8ff4563a015bd935c9b55dba14b2c1eb/shapely-2.0.1-cp39-cp39-win_amd64.whl
PILLOW_URL:=https://files.pythonhosted.org/packages/19/3f/b4d4bcf05dbcbe07f2e9613a8f4180c297395e73a91d8ad22c32c6624f8c/Pillow-9.2.0-cp39-cp39-win_amd64.whl
endif
ifeq ($(PYVERSION), py310)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/win-64/hpp-fcl-2.3.4-py310heb59267_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/win-64/eigenpy-3.1.0-py310hd146abe_0.conda
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/win-64/hpp-fcl-2.4.0-py310h1bf3f0a_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/win-64/eigenpy-3.2.0-py310h7fb871d_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/win-64/boost-1.78.0-py310h220cb41_4.tar.bz2
LXML_URL:=https://files.pythonhosted.org/packages/f6/71/65c80a4caa1617a4c6e8fe1500cebb179db96232e2f623bfe6a1f4294e39/lxml-4.8.0-cp310-cp310-win_amd64.whl
SHAPELY_URL:=https://files.pythonhosted.org/packages/81/8a/7ac076a86b2632f1872284c5e60ed5f2fc26094875a85b35d9fa17b52504/shapely-2.0.1-cp310-cp310-win_amd64.whl
PILLOW_URL:=https://files.pythonhosted.org/packages/02/55/67a3c17b9e7d972ed8c246f104da99ca4f3ea42fba566697e479011b84b6/Pillow-9.2.0-cp310-cp310-win_amd64.whl
endif
ifeq ($(PYVERSION), py311)
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/win-64/hpp-fcl-2.4.0-py311hd263b2c_0.conda
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/win-64/eigenpy-3.2.0-py311hd354db1_0.conda
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/win-64/boost-1.78.0-py311h12feb9d_3.tar.bz2
endif
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.2.5/download/win-64/assimp-5.2.5-h4dcb625_0.tar.bz2
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/win-64/qhull-2020.2-h70d2c02_2.tar.bz2
@@ -151,6 +166,33 @@ BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/win-64/
ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/win-64/zlib-1.2.11-h62dcd97_1010.tar.bz2
endif
LXML_NAME:=lxml
LXML_VER:=4.9.4
SHAPELY_NAME:=shapely
SHAPELY_VER:=2.0.2
PILLOW_NAME:=pillow
PILLOW_PKG_NAME:=Pillow
PILLOW_VER:=9.5.0
SHAPELY_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/s/$(SHAPELY_NAME)/$(SHAPELY_NAME)-$(SHAPELY_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(SHAPELY_ARCH).whl
PILLOW_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/p/$(PILLOW_NAME)/$(PILLOW_PKG_NAME)-$(PILLOW_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(PILLOW_ARCH).whl
ifeq ($(PLATFORM), macosm1)
ifeq ($(PYVERSION), py39)
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py39h0520ce3_1.tar.bz2
endif
ifeq ($(PYVERSION), py310)
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py310h02f21da_0.tar.bz2
endif
ifeq ($(PYVERSION), py311)
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py311h246f609_1.tar.bz2
endif
else
LXML_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/l/$(LXML_NAME)/$(LXML_NAME)-$(LXML_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(LXML_ARCH).whl
endif
$(info $$LXML_URL is [${LXML_URL}])
$(info $$SHAPELY_URL is [${SHAPELY_URL}])
$(info $$PILLOW_URL is [${PILLOW_URL}])
.PHONY: bump
bump:
cd . && $(SED) "s/$(OLD)/$(NEW)/" Makefile
@@ -169,7 +211,7 @@ endif
cp -r blenderbim/* dist/blenderbim/
# Provides IfcOpenShell Python functionality
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-9cc1f5f-$(PLATFORM)64.zip
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-6c9e130-$(PLATFORM)64.zip
cd dist/working && unzip ifcopenshell-python*
cp -r dist/working/ifcopenshell dist/blenderbim/libs/site/packages/
@@ -199,8 +241,10 @@ endif
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcbimtester/bimtester dist/blenderbim/libs/site/packages/
# Provides IFCTester functionality
cp -r dist/working/IfcOpenShell-0.7.0/src/ifctester/ifctester dist/blenderbim/libs/site/packages/
# Provides IFCCOBie functionality
cp -r dist/working/IfcOpenShell-0.7.0/src/ifccobie/* dist/blenderbim/libs/site/packages/
# Provides IFCFM functionality
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcfm/ifcfm dist/blenderbim/libs/site/packages/
# Provides bSDD functionality
cp -r dist/working/IfcOpenShell-0.7.0/src/bsdd/* dist/blenderbim/libs/site/packages/
# Provides IFCDiff functionality
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcdiff/* dist/blenderbim/libs/site/packages/
# Provides IFCCSV functionality
@@ -592,14 +636,6 @@ endif
cd dist/working/parse_type-0.5.2/ && cp -r parse_type ../../blenderbim/libs/site/packages/
rm -rf dist/working
# Required by IFCCOBie for XLSX support
# TODO: see if we can replace this with openpyxl which does both read/write
mkdir dist/working
cd dist/working && wget https://files.pythonhosted.org/packages/0c/bc/82d6783f83f65f56d8b77d052773c4a2f952fa86385f0cd54e1e006658d7/XlsxWriter-1.2.9.tar.gz
cd dist/working && tar -xzvf XlsxWriter*
cd dist/working/XlsxWriter-1.2.9/ && cp -r xlsxwriter ../../blenderbim/libs/site/packages/
rm -rf dist/working
# Required by augin
mkdir dist/working
cd dist/working && wget https://files.pythonhosted.org/packages/76/b4/b7baffbda025efd5dc8fcd8d2e953e3aa939c236a484084fa8f4c3588ee9/boto3-1.17.17.tar.gz
@@ -635,13 +671,6 @@ endif
cp -r dist/working/IFC2JSON_python-master/file_converters/ifcjson dist/blenderbim/libs/site/packages/
rm -rf dist/working
# Provides OpenLCA functionality
mkdir dist/working
cd dist/working && wget https://files.pythonhosted.org/packages/85/33/f91b96e9e8608ff65a003b692e8a9cdd60f2178f60617e5b1d21334c009c/olca-ipc-0.0.10.tar.gz
cd dist/working && tar -xzvf olca-ipc*
cd dist/working/olca-ipc-0.0.10/ && cp -r olca ../../blenderbim/libs/site/packages/
rm -rf dist/working
# Provides Brickschema functionality
mkdir dist/working
# For now lets bundle the latest nightly schema
@@ -667,6 +696,11 @@ endif
# Required for Desktop icon and file association
cp -r blenderbim/libs/desktop dist/blenderbim/libs/
# generate translations module for BBIM build
git clone https://github.com/IfcOpenShell/blenderbim-translations.git dist/working
python scripts/bbim_translations.py -i "dist/working" -o "dist/blenderbim"
rm -rf dist/working
# Remove dependencies also bundled with Blender
rm -rf dist/blenderbim/libs/site/packages/numpy
rm -rf dist/blenderbim/libs/site/packages/numpy.libs
+46 -31
View File
@@ -24,12 +24,17 @@ import blenderbim
import importlib
from . import handler, ui, prop, operator, helper
try:
from blenderbim.translations import translations_dict
except ImportError:
translations_dict = {}
cwd = os.path.dirname(os.path.realpath(__file__))
modules = {
"project": None,
"search": None,
"bcf": None,
"bsdd": None,
"root": None,
"unit": None,
"model": None,
@@ -43,8 +48,9 @@ modules = {
"spatial": None,
"void": None,
"aggregate": None,
"nest": None,
"geometry": None,
"cobie": None,
"fm": None,
"resource": None,
"cost": None,
"sequence": None,
@@ -66,7 +72,6 @@ modules = {
"document": None,
"pset_template": None,
"clash": None,
"lca": None,
"csv": None,
"tester": None,
"bimtester": None,
@@ -77,6 +82,7 @@ modules = {
"augin": None,
"debug": None,
"ifcgit": None,
"covering": None,
# Uncomment this line to enable loading of the demo module. Happy hacking!
# The name "demo" must correlate to a folder name in `bim/module/`.
# "demo": None,
@@ -90,28 +96,28 @@ for name in modules.keys():
classes = [
operator.AddIfcFile,
operator.BIM_OT_add_section_plane,
operator.BIM_OT_open_webbrowser,
operator.BIM_OT_remove_section_plane,
operator.BIM_OT_show_description,
operator.EditBlenderCollection,
operator.FileAssociate,
operator.FileUnassociate,
operator.OpenUpstream,
operator.OpenUri,
operator.SwitchTab,
operator.SetTab,
operator.ReloadIfcFile,
operator.RemoveIfcFile,
operator.SelectDataDir,
operator.SelectIfcFile,
operator.ReloadSelectedIfcFile,
operator.SelectSchemaDir,
operator.FileAssociate,
operator.FileUnassociate,
operator.SelectURIAttribute,
operator.EditBlenderCollection,
operator.BIM_OT_open_webbrowser,
operator.BIM_OT_show_description,
operator.SetTab,
operator.SwitchTab,
prop.StrProperty,
operator.BIM_OT_enum_property_search, # /!\ Register AFTER prop.StrProperty
prop.ObjProperty,
prop.Attribute,
prop.BIMAreaProperties,
prop.BIMTabProperties,
prop.BIMProperties,
prop.IfcParameter,
prop.PsetQto,
@@ -120,29 +126,38 @@ classes = [
prop.BIMCollectionProperties,
prop.BIMMaterialProperties,
prop.BIMMeshProperties,
prop.BIMFacet,
prop.BIMFilterGroup,
ui.BIM_UL_generic,
ui.BIM_UL_topics,
ui.BIM_ADDON_preferences,
# Project overview
ui.BIM_PT_project_info,
ui.BIM_PT_project_setup,
ui.BIM_PT_geometry,
ui.BIM_PT_tab_grouping_and_filtering,
# Tabs panel
ui.BIM_PT_tabs,
# Project overview
ui.BIM_PT_tab_project_info,
ui.BIM_PT_tab_project_setup,
ui.BIM_PT_tab_geometry,
ui.BIM_PT_tab_stakeholders,
ui.BIM_PT_tab_grouping_and_filtering,
# Object information
ui.BIM_PT_tab_object_metadata,
ui.BIM_PT_tab_misc,
# Geometry and materials
ui.BIM_PT_tab_placement,
ui.BIM_PT_tab_representations,
ui.BIM_PT_tab_geometric_relationships,
ui.BIM_PT_tab_parametric_geometry,
ui.BIM_PT_tab_profiles,
ui.BIM_PT_tab_materials,
ui.BIM_PT_tab_styles,
# Drawings and documents
ui.BIM_PT_tab_sheets,
ui.BIM_PT_tab_drawings,
ui.BIM_PT_tab_schedules,
ui.BIM_PT_tab_references,
# Services and systems
ui.BIM_PT_tab_services,
ui.BIM_PT_tab_services_object,
ui.BIM_PT_tab_zones,
# Structural analysis
ui.BIM_PT_tab_structural,
# Construction scheduling
@@ -169,6 +184,7 @@ addon_keymaps = []
icons = None
is_registering = False
last_commit_hash = "8888888"
overridden_scene_panels = dict()
def on_register(scene):
@@ -193,6 +209,7 @@ def register():
bpy.app.handlers.load_post.append(handler.loadIfcStore)
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
bpy.types.Screen.BIMAreaProperties = bpy.props.CollectionProperty(type=prop.BIMAreaProperties)
bpy.types.Screen.BIMTabProperties = bpy.props.PointerProperty(type=prop.BIMTabProperties)
bpy.types.Collection.BIMCollectionProperties = bpy.props.PointerProperty(type=prop.BIMCollectionProperties)
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
@@ -210,8 +227,8 @@ def register():
wm = bpy.context.window_manager
if wm.keyconfigs.addon:
km = wm.keyconfigs.addon.keymaps.new(name='Window', space_type='EMPTY')
kmi = km.keymap_items.new('bim.switch_tab', 'TAB', 'PRESS', ctrl=True)
km = wm.keyconfigs.addon.keymaps.new(name="Window", space_type="EMPTY")
kmi = km.keymap_items.new("bim.switch_tab", "TAB", "PRESS", ctrl=True)
addon_keymaps.append((km, kmi))
global icons
@@ -229,12 +246,16 @@ def register():
global last_commit_hash
try:
import git
path = Path(__file__).resolve().parent
repo = git.Repo(str(path), search_parent_directories=True)
last_commit_hash = repo.head.object.hexsha
except:
pass
bpy.app.translations.register("blenderbim", translations_dict)
def unregister():
global icons
@@ -271,16 +292,10 @@ def unregister():
km.keymap_items.remove(kmi)
addon_keymaps.clear()
for panel in [
"SCENE_PT_scene",
"SCENE_PT_unit",
"SCENE_PT_physics",
"SCENE_PT_rigid_body_world",
"SCENE_PT_audio",
"SCENE_PT_keying_sets",
"SCENE_PT_custom_props",
]:
try:
bpy.utils.unregister_class(getattr(handler, f"Override_{panel}"))
except:
pass
for panel in tuple(overridden_scene_panels.keys()):
original_panel, override_panel = overridden_scene_panels[panel]
bpy.utils.unregister_class(override_panel)
bpy.utils.register_class(original_panel)
del overridden_scene_panels[panel]
bpy.app.translations.unregister("blenderbim")
@@ -0,0 +1,993 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1');
FILE_NAME('/dev/null','2024-01-24T15:32:17+05:00',(),(),'IfcOpenShell v0.7.0-6c9e130ca','IfcOpenShell v0.7.0-6c9e130ca','Nobody');
FILE_SCHEMA(('IFC4'));
ENDSEC;
DATA;
#1=IFCPROJECT('3GRx5GJtv7EvI86hmjeQD6',$,'Landscape Assets Library',$,$,$,$,(#10,#14),#5);
#2=IFCPROJECTLIBRARY('1Go1D2HIr9AR4M6PdJb8DW',$,'Landscape Assets Library',$,$,$,$,$,$);
#3=IFCRELDECLARES('2Nc$sSRrvCzOJbe4Q6ZcVa',$,$,$,#1,(#2));
#4=IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.);
#5=IFCUNITASSIGNMENT((#4));
#6=IFCCARTESIANPOINT((0.,0.,0.));
#7=IFCDIRECTION((0.,0.,1.));
#8=IFCDIRECTION((1.,0.,0.));
#9=IFCAXIS2PLACEMENT3D(#6,#7,#8);
#10=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#9,$);
#11=IFCCARTESIANPOINT((0.,0.));
#12=IFCDIRECTION((1.,0.));
#13=IFCAXIS2PLACEMENT2D(#11,#12);
#14=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Plan',2,1.E-05,#13,$);
#15=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#10,$,.MODEL_VIEW.,$);
#16=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Plan',*,*,*,*,#14,$,.PLAN_VIEW.,$);
#17=IFCCARTESIANPOINTLIST2D(((-331.408782958984,488.559936523438),(-428.486114501953,371.370391845703),(-408.744873046875,331.425659179688),(-492.345001220703,263.470184326172),(-519.991760253906,89.2266616821289),(-366.53076171875,65.1004943847656),(-523.9287109375,51.0255508422852),(-542.778625488281,-161.150390625),(-455.430816650391,-198.061676025391),(-467.317413330078,-264.261047363281),(-389.842987060547,-378.319213867188),(-351.178894042969,-382.372741699219),(-243.823715209961,-498.601684570312),(-171.287063598633,-509.852447509766),(-182.036499023438,-454.125518798828),(-123.127815246582,-538.493591308594),(208.583557128906,-495.693969726562),(174.199142456055,-387.101898193359),(269.968353271484,-457.362365722656),(517.720397949219,-208.39501953125),(467.592559814453,-165.981643676758),(535.54443359375,-138.483825683594),(546.240173339844,47.7887229919434),(425.388610839844,29.4520435333252),(514.287658691406,107.907821655273),(467.776489257812,312.002685546875),(374.896423339844,365.066589355469),(325.083190917969,461.613433837891),(224.657806396484,496.0244140625),(105.845329284668,424.517761230469),(191.164672851562,514.677307128906),(-7.41858577728271,553.592407226562),(-105.371849060059,531.902709960938),(-180.417175292969,499.200317382812)));
#18=IFCINDEXEDPOLYCURVE(#17,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#19=IFCCARTESIANPOINTLIST3D(((80.,0.,0.),(40.,69.2820323027551,0.),(-40.,69.2820323027551,0.),(-80.,9.79717439317883E-15,0.),(-40.,-69.2820323027551,0.),(40.,-69.2820323027551,0.),(80.,0.,280.),(40.,69.2820323027551,280.),(-40.,69.2820323027551,280.),(-80.,9.79717439317883E-15,280.),(-40.,-69.2820323027551,280.),(40.,-69.2820323027551,280.),(570.140986817674,-5.11998806339175,502.765430824539),(261.339072714044,511.863483235935,520.441255965265),(-271.449977559115,464.840881207563,498.631051036932),(-577.400357563209,-18.0002392785791,529.745674601363),(-246.747896537159,-522.096293601777,523.07445182747),(289.929723989709,-497.828722152031,481.563368832141),(502.264135660384,-3.10815712380199,727.667741239885),(256.486268377103,397.638199139059,733.570036889682),(-210.099579404528,457.859720268934,722.445245365077),(-522.479901100414,-35.7080296205946,687.931736233252),(-213.081169792834,-438.257812253687,704.648197605265),(273.503462940155,-437.429578762916,717.812431534607),(409.72756228227,-31.3204193188668,937.51589967911),(231.939555298324,334.085354425246,911.578097173966),(-213.440011711198,325.481782873574,931.184023328963),(-391.4385670944,11.3681475906559,933.839400395571),(-181.597613330968,-384.045646583411,936.269525762716),(198.107253544529,-351.52926490917,903.558501964971),(358.836914477244,-29.0443800107266,1124.54961826854),(191.636382145782,325.816574427016,1143.76409675514),(-175.686180114122,275.257306965059,1132.35007279295),(-330.55780048986,-23.1508504281077,1121.17416888324),(-172.687090174965,-317.707089809191,1159.279616419),(192.616008554028,-273.601791847896,1147.14103266758),(252.691797114565,-4.70084047240072,1330.07490310776),(147.138603790187,216.221351494253,1352.71275883304),(-162.078730999078,224.60205813657,1371.67941135993),(-271.544406853979,26.607279268613,1378.19571732018),(-150.451939922955,-226.516554345382,1395.27272058484),(133.281231324475,-220.990480915293,1334.23398662872),(187.5691337229,-2.77622907865673,1575.7384942221),(88.4380124532162,169.216774598146,1585.64117034361),(-94.8941720337192,139.038794764388,1578.6341137138),(-154.588503036945,-6.10749408831602,1549.40002660187),(-129.962875945536,-160.551322551302,1550.49839466833),(64.8441918513045,-191.270989336927,1579.55078264226),(0.05,0.,1800.),(0.025,0.0433012701892219,1800.),(-0.025,0.0433012701892219,1800.),(-0.05,6.12323399573677E-18,1800.),(-0.025,-0.0433012701892219,1800.),(0.025,-0.0433012701892219,1800.)));
#20=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#21=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#22=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#23=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#24=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#25=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#26=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#27=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#28=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#29=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#30=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#31=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#32=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#33=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#34=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#35=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#36=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#37=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#38=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#39=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#40=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#41=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#42=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#43=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#44=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#45=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#46=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#47=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#48=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#49=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#50=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#51=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#52=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#53=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#54=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#55=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#56=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#57=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#58=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#59=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#60=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#61=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#62=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#63=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#64=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#65=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#66=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#67=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#68=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#69=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#70=IFCPOLYGONALFACESET(#19,$,(#20,#21,#22,#23,#24,#25,#26,#27,#28,#29,#30,#31,#32,#33,#34,#35,#36,#37,#38,#39,#40,#41,#42,#43,#44,#45,#46,#47,#48,#49,#50,#51,#52,#53,#54,#55,#56,#57,#58,#59,#60,#61,#62,#63,#64,#65,#66,#67,#68,#69),$);
#71=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#18));
#72=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#70));
#73=IFCGEOGRAPHICELEMENTTYPE('34zHVx8cX0dRoaynJ1QKTg',$,'Cone Tree (1.8m)',$,$,$,(#78,#83),$,$,.NOTDEFINED.);
#74=IFCCARTESIANPOINT((0.,0.,0.));
#75=IFCDIRECTION((1.,0.,0.));
#76=IFCDIRECTION((0.,0.,1.));
#77=IFCAXIS2PLACEMENT3D(#74,#76,#75);
#78=IFCREPRESENTATIONMAP(#77,#72);
#79=IFCCARTESIANPOINT((0.,0.,0.));
#80=IFCDIRECTION((1.,0.,0.));
#81=IFCDIRECTION((0.,0.,1.));
#82=IFCAXIS2PLACEMENT3D(#79,#81,#80);
#83=IFCREPRESENTATIONMAP(#82,#71);
#84=IFCRELDECLARES('2hc5gFJQT6VP_pTBscCuS_',$,$,$,#2,(#840,#409,#680,#208,#613,#73,#342,#773,#275,#479,#742,#907,#711,#141,#546,#974,#444));
#85=IFCCARTESIANPOINTLIST2D(((-1281.64282226562,1889.38659667969),(-1657.06579589844,1436.1845703125),(-1580.72131347656,1281.70812988281),(-1904.02453613281,1018.90686035156),(-2010.94165039062,345.062408447266),(-1417.46850585938,251.760314941406),(-2026.16674804688,197.328903198242),(-2099.06420898438,-623.209899902344),(-1761.26782226562,-765.955322265625),(-1807.236328125,-1021.96527099609),(-1507.62292480469,-1463.05749511719),(-1358.09887695312,-1478.73352050781),(-942.928833007812,-1928.220703125),(-662.411010742188,-1971.73022460938),(-703.981872558594,-1756.21984863281),(-476.166870117188,-2082.49291992188),(806.646179199219,-1916.97583007812),(673.672790527344,-1497.02233886719),(1044.03686523438,-1768.73767089844),(2002.15771484375,-805.917053222656),(1808.30041503906,-641.893615722656),(2071.087890625,-535.552490234375),(2112.45092773438,184.811248779297),(1645.0869140625,113.898612976074),(1988.88244628906,417.307220458984),(1809.01171875,1206.59436035156),(1449.82067871094,1411.80627441406),(1257.18005371094,1785.17761230469),(868.809387207031,1918.25366210938),(409.3310546875,1641.71911621094),(739.282836914062,1990.38916015625),(-28.6895751953125,2140.8837890625),(-407.5,2057.00415039062),(-697.719543457031,1930.53576660156)));
#86=IFCINDEXEDPOLYCURVE(#85,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#87=IFCCARTESIANPOINTLIST3D(((220.,0.,0.),(110.,190.525588832576,0.),(-110.,190.525588832577,0.),(-220.,2.69422295812418E-14,0.),(-110.,-190.525588832576,0.),(110.,-190.525588832576,0.),(220.,0.,740.),(110.,190.525588832576,740.),(-110.,190.525588832577,740.),(-220.,2.69422295812418E-14,740.),(-110.,-190.525588832576,740.),(110.,-190.525588832576,740.),(2227.84155681395,-42.6665671949312,2823.99763782354),(916.158939283701,2080.25825808339,2971.29618066292),(-1000.41647965929,1688.40324118029,2789.54447292681),(-2288.33631302674,-150.00199398816,3048.8330026304),(-794.565804476328,-2165.53167779874,2993.23947951463),(1154.41436658091,-1963.30191571753,2647.31378788689),(1998.64557494764,-25.9013093650166,4925.80260557047),(1043.94112536474,1419.75032646046,4974.98840265211),(-657.385383926618,1921.59633587608,4882.28180661374),(-2167.11028694789,-297.566913504955,4594.66923051519),(-682.231970495834,-1758.24710241569,4733.97307528197),(1185.75108005685,-1751.34515665926,4843.67502469316),(1563.95190790781,-261.00349432389,6902.15630684973),(1007.60740526381,1181.51272302971,6686.0079526402),(-853.444542037762,1109.81629343244,6849.3906705985),(-1411.54361467555,94.7345632554656,6871.51881282023),(-588.091222202507,-1597.84849101442,6891.76985754645),(725.67155731552,-1326.87864372908,6619.17799256523),(1476.3076206437,-242.036500089388,8688.38967604738),(839.969851214854,1403.97565889549,8848.51033010232),(-707.051500951019,982.648430045852,8753.39346375077),(-1240.6483374155,-192.923753567565,8660.26093116989),(-682.059084791378,-1336.39662041362,8977.80632730116),(848.133404616898,-968.852470736159,8876.65146270604),(928.209420399157,-39.1736706033394,10628.7194306599),(637.377253807116,782.05157030683,10817.3682283706),(-761.878313881205,851.890792326142,10975.4236660946),(-1085.31450156094,221.727327238442,11029.7262157634),(-664.988388246851,-867.844927399578,11172.0345763022),(521.899149926181,-821.794315482163,10663.3784600012),(721.965003246392,-23.1352423221394,12903.5350708985),(316.42788155458,681.716198690303,12986.057371911),(-370.229211392105,430.233033408991,12927.6652333293),(-447.126414196768,-50.8957840693003,12684.0478407298),(-662.468410657245,-609.504098299938,12693.2009079504),(119.812709871982,-865.501321513485,12935.3041410664),(0.05,0.,15000.),(0.025,0.0433012701892219,15000.),(-0.025,0.0433012701892219,15000.),(-0.05,6.12323399573677E-18,15000.),(-0.025,-0.0433012701892219,15000.),(0.025,-0.0433012701892219,15000.)));
#88=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#89=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#90=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#91=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#92=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#93=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#94=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#95=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#96=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#97=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#98=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#99=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#100=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#101=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#102=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#103=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#104=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#105=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#106=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#107=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#108=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#109=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#110=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#111=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#112=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#113=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#114=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#115=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#116=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#117=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#118=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#119=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#120=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#121=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#122=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#123=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#124=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#125=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#126=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#127=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#128=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#129=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#130=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#131=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#132=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#133=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#134=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#135=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#136=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#137=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#138=IFCPOLYGONALFACESET(#87,$,(#88,#89,#90,#91,#92,#93,#94,#95,#96,#97,#98,#99,#100,#101,#102,#103,#104,#105,#106,#107,#108,#109,#110,#111,#112,#113,#114,#115,#116,#117,#118,#119,#120,#121,#122,#123,#124,#125,#126,#127,#128,#129,#130,#131,#132,#133,#134,#135,#136,#137),$);
#139=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#86));
#140=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#138));
#141=IFCGEOGRAPHICELEMENTTYPE('1up5YjiS1CSvOopNo9qhzA',$,'Cone Tree (15m)',$,$,$,(#146,#151),$,$,.NOTDEFINED.);
#142=IFCCARTESIANPOINT((0.,0.,0.));
#143=IFCDIRECTION((1.,0.,0.));
#144=IFCDIRECTION((0.,0.,1.));
#145=IFCAXIS2PLACEMENT3D(#142,#144,#143);
#146=IFCREPRESENTATIONMAP(#145,#140);
#147=IFCCARTESIANPOINT((0.,0.,0.));
#148=IFCDIRECTION((1.,0.,0.));
#149=IFCDIRECTION((0.,0.,1.));
#150=IFCAXIS2PLACEMENT3D(#147,#149,#148);
#151=IFCREPRESENTATIONMAP(#150,#139);
#152=IFCCARTESIANPOINTLIST2D(((-498.579620361328,735.001647949219),(-644.625122070312,558.698791503906),(-614.925903320312,498.60498046875),(-740.696044921875,396.37109375),(-782.288513183594,134.234802246094),(-551.41796875,97.9387969970703),(-788.211303710938,76.7640991210938),(-816.569641113281,-242.43864440918),(-685.161376953125,-297.968902587891),(-703.043884277344,-397.560852050781),(-586.489440917969,-569.15283203125),(-528.322204589844,-575.251037597656),(-366.814422607422,-750.108703613281),(-257.688507080078,-767.03466796875),(-273.860229492188,-683.197692871094),(-185.236541748047,-810.123107910156),(313.798278808594,-745.734313964844),(262.069519042969,-582.365661621094),(406.147064208984,-688.067260742188),(778.871398925781,-313.5146484375),(703.457824707031,-249.706893920898),(805.686340332031,-208.338500976562),(821.777282714844,71.8945388793945),(639.965148925781,44.3083839416504),(773.707153320312,162.339202880859),(703.734558105469,469.384552001953),(564.003479003906,549.215209960938),(489.063201904297,694.462707519531),(337.980773925781,746.2314453125),(159.236328125,638.655029296875),(287.592864990234,774.293273925781),(-11.1607036590576,832.838073730469),(-158.524017333984,800.207580566406),(-271.424072265625,751.009338378906)));
#153=IFCINDEXEDPOLYCURVE(#152,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#154=IFCCARTESIANPOINTLIST3D(((110.,0.,0.),(55.,95.2627944162882,0.),(-55.,95.2627944162883,0.),(-110.,1.34711147906209E-14,0.),(-55.,-95.2627944162882,0.),(55.,-95.2627944162882,0.),(110.,0.,320.),(55.,95.2627944162882,320.),(-55.,95.2627944162883,320.),(-110.,1.34711147906209E-14,320.),(-55.,-95.2627944162882,320.),(55.,-95.2627944162882,320.),(864.280518937983,-14.2221890649771,1004.18968879832),(366.2196464279,798.785843488237,1053.28920307812),(-394.305493219765,668.167504520537,992.705300499414),(-884.445437675581,-50.0006646627198,1079.13481040061),(-325.688601492109,-827.210316726686,1060.60363602869),(445.638122193637,-759.800396032949,945.295072152772),(771.659636093658,-8.63376978833887,1694.31515423778),(400.702597343804,564.567676396979,1710.71041993166),(-271.850683531095,731.84967953552,1679.8082212522),(-827.814540093743,-99.1889711683184,1583.93736255268),(-280.132879054167,-677.399935048722,1630.37197747494),(447.972582241171,-675.099286463246,1666.93929394534),(610.539524858158,-87.0011647746299,2342.62353085467),(380.480246199047,471.106285369781,2270.57407945149),(-329.092625123698,447.207475504026,2325.0349854376),(-559.736760447407,31.5781877518219,2332.41103284484),(-240.641518511947,-609.88487469802,2339.16138108691),(286.501630216284,-519.561592269572,2248.29742609317),(565.102540214566,-80.6788333631295,2927.55846344436),(316.489950404951,531.211740774762,2980.93201479601),(-272.18383365034,390.769331158215,2949.22639267883),(-486.549445805167,-64.3079178558549,2918.18221515187),(-263.853028263793,-508.685394614137,3024.03068052896),(319.211134872299,-386.170678054984,2990.31239233058),(366.18091791083,-13.0578902011131,3563.85885783901),(240.847973491261,309.854854694926,3626.74179040925),(-282.348326849291,333.134595368031,3679.42693631726),(-418.54927829809,73.9091090794806,3697.52778620685),(-250.051684971173,-338.452640392509,3744.96390638646),(202.355272197616,-323.102436420037,3575.41186761945),(281.210556637686,-7.71174744071313,4311.65454744235),(125.753738295971,262.36087427247,4339.1619811132),(-143.687514908479,178.533152512032,4319.69793491929),(-189.597693621145,-16.9652613564334,4238.49213738614),(-241.100581330193,-238.290174142348,4241.54315979299),(60.215347735105,-323.622581880197,4322.24423749834),(0.05,0.,5000.),(0.025,0.0433012701892219,5000.),(-0.025,0.0433012701892219,5000.),(-0.05,6.12323399573677E-18,5000.),(-0.025,-0.0433012701892219,5000.),(0.025,-0.0433012701892219,5000.)));
#155=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#156=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#157=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#158=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#159=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#160=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#161=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#162=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#163=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#164=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#165=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#166=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#167=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#168=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#169=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#170=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#171=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#172=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#173=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#174=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#175=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#176=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#177=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#178=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#179=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#180=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#181=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#182=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#183=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#184=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#185=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#186=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#187=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#188=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#189=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#190=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#191=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#192=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#193=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#194=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#195=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#196=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#197=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#198=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#199=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#200=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#201=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#202=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#203=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#204=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#205=IFCPOLYGONALFACESET(#154,$,(#155,#156,#157,#158,#159,#160,#161,#162,#163,#164,#165,#166,#167,#168,#169,#170,#171,#172,#173,#174,#175,#176,#177,#178,#179,#180,#181,#182,#183,#184,#185,#186,#187,#188,#189,#190,#191,#192,#193,#194,#195,#196,#197,#198,#199,#200,#201,#202,#203,#204),$);
#206=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#153));
#207=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#205));
#208=IFCGEOGRAPHICELEMENTTYPE('1cYi681Jz1UQcLu0VCPumj',$,'Cone Tree (5m)',$,$,$,(#213,#218),$,$,.NOTDEFINED.);
#209=IFCCARTESIANPOINT((0.,0.,0.));
#210=IFCDIRECTION((1.,0.,0.));
#211=IFCDIRECTION((0.,0.,1.));
#212=IFCAXIS2PLACEMENT3D(#209,#211,#210);
#213=IFCREPRESENTATIONMAP(#212,#207);
#214=IFCCARTESIANPOINT((0.,0.,0.));
#215=IFCDIRECTION((1.,0.,0.));
#216=IFCDIRECTION((0.,0.,1.));
#217=IFCAXIS2PLACEMENT3D(#214,#216,#215);
#218=IFCREPRESENTATIONMAP(#217,#206);
#219=IFCCARTESIANPOINTLIST2D(((-117.312850952148,172.941558837891),(-151.676498413086,131.458541870117),(-144.688446044922,117.318817138672),(-174.28141784668,93.263786315918),(-184.067886352539,31.584659576416),(-129.745407104492,23.0444221496582),(-185.461486816406,18.062141418457),(-192.134033203125,-57.0443878173828),(-161.214447021484,-70.1103286743164),(-165.422088623047,-93.5437316894531),(-137.997512817383,-133.918304443359),(-124.311111450195,-135.353179931641),(-86.3092803955078,-176.496170043945),(-60.6325874328613,-180.478744506836),(-64.4376983642578,-160.752395629883),(-43.5850677490234,-190.617202758789),(73.8348922729492,-175.466888427734),(61.6634140014648,-137.027221679688),(95.5640106201172,-161.898178100586),(183.263854980469,-73.7681503295898),(165.519485473633,-58.7545623779297),(189.573257446289,-49.020824432373),(193.359359741211,16.9163608551025),(150.580032348633,10.4255018234253),(182.048736572266,38.1974563598633),(165.584594726562,110.443428039551),(132.706695556641,129.227111816406),(115.073692321777,163.402984619141),(79.5248870849609,175.583862304688),(37.4673728942871,150.271774291992),(67.6689071655273,182.186645507812),(-2.62604808807373,195.961898803711),(-37.2997703552246,188.284133911133),(-63.8644866943359,176.708084106445)));
#220=IFCINDEXEDPOLYCURVE(#219,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#221=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(189.142441515039,-1.13777512519817,58.3923179610087),(89.297571714232,167.825915933192,62.3202791033923),(-91.5444394575811,157.376448815776,57.4735668970959),(-190.755635014047,-4.00005317301757,64.3879276891917),(-86.0550881193688,-170.099873792268,62.9054337394378),(95.651049775491,-164.707080136769,53.6807486293646),(196.799437554159,-0.69070158306711,117.259498053308),(99.5895411208377,162.136578649577,118.571119308818),(-89.2813880158209,175.51913890066,116.098943414462),(-201.291829874166,-7.93511769346546,108.4292747185),(-89.9439636576667,-171.163159341716,112.144043912281),(103.371139912627,-170.979107454878,115.069429229913),(198.976495321986,-6.96009318197039,172.781311039802),(105.50508636259,167.707783451086,167.017354927548),(-101.394076676563,165.795878661826,171.374227406436),(-194.912274169126,2.52625502014577,171.964311199016),(-94.3179881476225,-178.810070597345,172.504339058381),(97.9867970839694,-171.58420800307,165.235222658882),(198.408203217165,-6.45430666905036,223.233248504121),(101.919196032396,175.172031121757,227.503132612252),(-98.3747066920271,163.936638352433,224.966682842878),(-192.123955664413,-5.14463342846837,222.483148640721),(-97.7082422611035,-173.369923428907,230.951025870888),(102.136890789784,-163.568746104175,228.253562815018),(185.561140099533,-1.04463121608905,277.794422912835),(97.4011712126342,160.119291473642,282.825057518454),(-100.721199481277,161.981670727491,287.039869191095),(-189.750608930514,5.91272872635847,288.487937182262),(-98.1374681310272,-162.407114329449,292.282826796631),(94.3217551091426,-161.179098011651,278.71866369527),(181.830177864348,-0.61693979525705,341.275220938245),(89.7269657303444,158.975584278118,343.475815631913),(-91.161667859345,152.269366537283,341.9186919364),(-174.501148823025,-1.35722090851465,335.422228133748),(-98.9547131730822,-157.049928267708,335.666309926296),(84.4838944854751,-163.876520886736,342.122396142724),(0.05,0.,400.),(0.025,0.0433012701892219,400.),(-0.025,0.0433012701892219,400.),(-0.05,6.12323399573677E-18,400.),(-0.025,-0.0433012701892219,400.),(0.025,-0.0433012701892219,400.)));
#222=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#223=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#224=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#225=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#226=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#227=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#228=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#229=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#230=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#231=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#232=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#233=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#234=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#235=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#236=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#237=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#238=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#239=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#240=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#241=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#242=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#243=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#244=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#245=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#246=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#247=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#248=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#249=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#250=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#251=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#252=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#253=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#254=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#255=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#256=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#257=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#258=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#259=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#260=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#261=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#262=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#263=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#264=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#265=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#266=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#267=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#268=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#269=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#270=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#271=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#272=IFCPOLYGONALFACESET(#221,$,(#222,#223,#224,#225,#226,#227,#228,#229,#230,#231,#232,#233,#234,#235,#236,#237,#238,#239,#240,#241,#242,#243,#244,#245,#246,#247,#248,#249,#250,#251,#252,#253,#254,#255,#256,#257,#258,#259,#260,#261,#262,#263,#264,#265,#266,#267,#268,#269,#270,#271),$);
#273=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#220));
#274=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#272));
#275=IFCGEOGRAPHICELEMENTTYPE('1mO0fZa2b4sflxAiM3QTIb',$,'Hedge Small (0.4m)',$,$,$,(#280,#285),$,$,.NOTDEFINED.);
#276=IFCCARTESIANPOINT((0.,0.,0.));
#277=IFCDIRECTION((1.,0.,0.));
#278=IFCDIRECTION((0.,0.,1.));
#279=IFCAXIS2PLACEMENT3D(#276,#278,#277);
#280=IFCREPRESENTATIONMAP(#279,#274);
#281=IFCCARTESIANPOINT((0.,0.,0.));
#282=IFCDIRECTION((1.,0.,0.));
#283=IFCDIRECTION((0.,0.,1.));
#284=IFCAXIS2PLACEMENT3D(#281,#283,#282);
#285=IFCREPRESENTATIONMAP(#284,#273);
#286=IFCCARTESIANPOINTLIST2D(((-234.625701904297,345.883117675781),(-303.352996826172,262.917083740234),(-289.376892089844,234.637634277344),(-348.562835693359,186.527572631836),(-368.135772705078,63.169319152832),(-259.490814208984,46.0888442993164),(-370.922973632812,36.1242828369141),(-384.26806640625,-114.088775634766),(-322.428894042969,-140.220657348633),(-330.844177246094,-187.087463378906),(-275.995025634766,-267.836608886719),(-248.622222900391,-270.706359863281),(-172.618560791016,-352.992340087891),(-121.265174865723,-360.957489013672),(-128.875396728516,-321.504791259766),(-87.1701354980469,-381.234405517578),(147.669784545898,-350.933776855469),(123.32682800293,-274.054443359375),(191.128021240234,-323.796356201172),(366.527709960938,-147.53630065918),(331.038970947266,-117.509124755859),(379.146514892578,-98.0416488647461),(386.718719482422,33.8327217102051),(301.160064697266,20.8510036468506),(364.097473144531,76.3949127197266),(331.169189453125,220.886856079102),(265.413391113281,258.454223632812),(230.147384643555,326.805969238281),(159.049774169922,351.167724609375),(74.9347457885742,300.543548583984),(135.337814331055,364.373291015625),(-5.25209617614746,391.923797607422),(-74.5995407104492,376.568267822266),(-127.728973388672,353.416168212891)));
#287=IFCINDEXEDPOLYCURVE(#286,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#288=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(378.284883030077,-2.27555025039633,116.784635922017),(178.595143428464,335.651831866383,124.640558206785),(-183.088878915162,314.752897631551,114.947133794192),(-381.511270028093,-8.00010634603514,128.775855378383),(-172.110176238738,-340.199747584535,125.810867478876),(191.302099550982,-329.414160273537,107.361497258729),(393.598875108319,-1.38140316613422,234.518996106616),(199.179082241675,324.273157299153,237.142238617636),(-178.562776031642,351.03827780132,232.197886828923),(-402.583659748332,-15.8702353869309,216.858549437001),(-179.887927315333,-342.326318683432,224.288087824562),(206.742279825254,-341.958214909756,230.138858459826),(397.952990643972,-13.9201863639408,345.562622079605),(211.010172725181,335.415566902172,334.034709855096),(-202.788153353125,331.591757323652,342.748454812872),(-389.824548338252,5.05251004029154,343.928622398032),(-188.635976295245,-357.620141194691,345.008678116763),(195.973594167939,-343.168416006139,330.470445317765),(396.81640643433,-12.9086133381007,446.466497008241),(203.838392064792,350.344062243514,455.006265224505),(-196.749413384054,327.873276704866,449.933365685756),(-384.247911328827,-10.2892668569367,444.966297281442),(-195.416484522207,-346.739846857814,461.902051741776),(204.273781579568,-327.137492208349,456.507125630036),(371.122280199066,-2.0892624321781,555.588845825671),(194.802342425268,320.238582947285,565.650115036909),(-201.442398962553,323.963341454982,574.07973838219),(-379.501217861028,11.8254574527169,576.975874364524),(-196.274936262054,-324.814228658898,584.565653593263),(188.643510218285,-322.358196023303,557.43732739054),(363.660355728696,-1.2338795905141,682.550441876491),(179.453931460689,317.951168556236,686.951631263826),(-182.32333571869,304.538733074566,683.837383872801),(-349.00229764605,-2.71444181702931,670.844456267496),(-197.909426346164,-314.099856535417,671.332619852593),(168.96778897095,-327.753041773473,684.244792285448),(0.05,0.,800.),(0.025,0.0433012701892219,800.),(-0.025,0.0433012701892219,800.),(-0.05,6.12323399573677E-18,800.),(-0.025,-0.0433012701892219,800.),(0.025,-0.0433012701892219,800.)));
#289=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#290=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#291=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#292=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#293=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#294=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#295=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#296=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#297=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#298=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#299=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#300=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#301=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#302=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#303=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#304=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#305=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#306=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#307=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#308=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#309=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#310=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#311=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#312=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#313=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#314=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#315=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#316=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#317=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#318=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#319=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#320=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#321=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#322=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#323=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#324=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#325=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#326=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#327=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#328=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#329=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#330=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#331=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#332=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#333=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#334=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#335=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#336=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#337=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#338=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#339=IFCPOLYGONALFACESET(#288,$,(#289,#290,#291,#292,#293,#294,#295,#296,#297,#298,#299,#300,#301,#302,#303,#304,#305,#306,#307,#308,#309,#310,#311,#312,#313,#314,#315,#316,#317,#318,#319,#320,#321,#322,#323,#324,#325,#326,#327,#328,#329,#330,#331,#332,#333,#334,#335,#336,#337,#338),$);
#340=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#287));
#341=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#339));
#342=IFCGEOGRAPHICELEMENTTYPE('1esPZTKFXE3Af39$mWJyUW',$,'Hedge Medium (0.8m)',$,$,$,(#347,#352),$,$,.NOTDEFINED.);
#343=IFCCARTESIANPOINT((0.,0.,0.));
#344=IFCDIRECTION((1.,0.,0.));
#345=IFCDIRECTION((0.,0.,1.));
#346=IFCAXIS2PLACEMENT3D(#343,#345,#344);
#347=IFCREPRESENTATIONMAP(#346,#341);
#348=IFCCARTESIANPOINT((0.,0.,0.));
#349=IFCDIRECTION((1.,0.,0.));
#350=IFCDIRECTION((0.,0.,1.));
#351=IFCAXIS2PLACEMENT3D(#348,#350,#349);
#352=IFCREPRESENTATIONMAP(#351,#340);
#353=IFCCARTESIANPOINTLIST2D(((-527.907836914062,778.237060546875),(-682.544250488281,591.5634765625),(-651.098022460938,527.934692382812),(-784.266357421875,419.687042236328),(-828.305480957031,142.130966186523),(-583.854309082031,103.699897766113),(-834.57666015625,81.2796401977539),(-864.603149414062,-256.699737548828),(-725.465026855469,-315.496459960938),(-744.3994140625,-420.946807861328),(-620.988830566406,-602.632385253906),(-559.400024414062,-609.08935546875),(-388.391754150391,-794.232788085938),(-272.846649169922,-812.154357910156),(-289.969635009766,-723.3857421875),(-196.1328125,-857.777404785156),(332.257019042969,-789.601013183594),(277.4853515625,-616.622497558594),(430.038055419922,-728.541809082031),(824.687377929688,-331.956665039062),(744.837707519531,-264.395538330078),(853.079650878906,-220.593704223633),(870.117126464844,76.1236267089844),(677.610168457031,46.9147605895996),(819.219299316406,171.888565063477),(745.130676269531,496.995422363281),(597.18017578125,581.522033691406),(517.831604003906,735.313415527344),(357.861999511719,790.127380371094),(168.603179931641,676.222961425781),(304.510101318359,819.839904785156),(-11.8172159194946,881.828552246094),(-167.848968505859,847.278625488281),(-287.390197753906,795.186340332031)));
#354=IFCINDEXEDPOLYCURVE(#353,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#355=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(851.140986817674,-5.11998806339175,262.765430824539),(401.839072714044,755.216621699362,280.441255965265),(-411.949977559115,708.19401967099,258.631051036932),(-858.400357563209,-18.0002392785791,289.745674601363),(-387.24789653716,-765.449432065204,283.07445182747),(430.429723989709,-741.181860615459,241.563368832141),(885.597468993717,-3.10815712380199,527.667741239885),(448.152935043769,729.614603923094,533.570036889682),(-401.766246071194,789.836125052969,522.445245365077),(-905.813234433747,-35.7080296205946,487.931736233252),(-404.7478364595,-770.234217037722,504.648197605265),(465.170129606822,-769.40598354695,517.812431534608),(895.394228948937,-31.3204193188668,777.515899679111),(474.772888631657,754.685025529888,751.578097173967),(-456.273345044531,746.081453978216,771.184023328963),(-877.105233761067,11.368147590656,773.839400395571),(-424.430946664301,-804.645317688054,776.269525762717),(440.940586877863,-772.128936013813,743.558501964971),(892.836914477244,-29.0443800107266,1004.54961826854),(458.636382145783,788.274140047906,1023.76409675514),(-442.686180114122,737.714872585949,1012.35007279295),(-864.55780048986,-23.1508504281077,1001.17416888324),(-439.687090174966,-780.164655430081,1039.279616419),(459.616008554028,-736.059357468786,1027.14103266758),(835.025130447899,-4.70084047240072,1250.07490310776),(438.305270456854,720.536811631391,1272.71275883304),(-453.245397665745,728.917518273708,1291.67941135993),(-853.877740187312,26.6072792686131,1298.19571732018),(-441.618606589622,-730.832014482521,1315.27272058484),(424.447897991142,-725.305941052431,1254.23398662872),(818.235800389567,-2.77622907865673,1535.7384942221),(403.77134578655,715.390129251532,1545.64117034361),(-410.227505367052,685.212149417774,1538.6341137138),(-785.255169703612,-6.10749408831594,1509.40002660187),(-445.29620927887,-706.724677204688,1510.49839466833),(380.177525184638,-737.444343990313,1539.55078264226),(0.05,0.,1800.),(0.025,0.0433012701892219,1800.),(-0.025,0.0433012701892219,1800.),(-0.05,6.12323399573677E-18,1800.),(-0.025,-0.0433012701892219,1800.),(0.025,-0.0433012701892219,1800.)));
#356=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#357=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#358=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#359=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#360=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#361=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#362=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#363=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#364=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#365=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#366=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#367=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#368=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#369=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#370=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#371=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#372=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#373=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#374=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#375=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#376=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#377=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#378=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#379=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#380=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#381=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#382=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#383=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#384=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#385=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#386=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#387=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#388=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#389=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#390=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#391=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#392=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#393=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#394=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#395=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#396=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#397=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#398=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#399=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#400=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#401=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#402=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#403=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#404=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#405=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#406=IFCPOLYGONALFACESET(#355,$,(#356,#357,#358,#359,#360,#361,#362,#363,#364,#365,#366,#367,#368,#369,#370,#371,#372,#373,#374,#375,#376,#377,#378,#379,#380,#381,#382,#383,#384,#385,#386,#387,#388,#389,#390,#391,#392,#393,#394,#395,#396,#397,#398,#399,#400,#401,#402,#403,#404,#405),$);
#407=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#354));
#408=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#406));
#409=IFCGEOGRAPHICELEMENTTYPE('2ITyucrb9DnxtmPeA_FCBG',$,'Hedge Big (1.8m)',$,$,$,(#414,#419),$,$,.NOTDEFINED.);
#410=IFCCARTESIANPOINT((0.,0.,0.));
#411=IFCDIRECTION((1.,0.,0.));
#412=IFCDIRECTION((0.,0.,1.));
#413=IFCAXIS2PLACEMENT3D(#410,#412,#411);
#414=IFCREPRESENTATIONMAP(#413,#408);
#415=IFCCARTESIANPOINT((0.,0.,0.));
#416=IFCDIRECTION((1.,0.,0.));
#417=IFCDIRECTION((0.,0.,1.));
#418=IFCAXIS2PLACEMENT3D(#415,#417,#416);
#419=IFCREPRESENTATIONMAP(#418,#407);
#420=IFCCARTESIANPOINTLIST3D(((-2517.70166015625,-2646.30053710938,3901.58129882812),(-255.675521850586,-1248.60815429688,5000.),(-1133.70935058594,-349.566070556641,4688.61865234375),(0.,0.,4658.5205078125),(3472.91040039062,-1142.93579101562,3901.58129882812),(1250.74682617188,317.302124023438,5000.),(806.568603515625,-858.251220703125,4688.61865234375),(1171.36364746094,3483.57202148438,3901.58129882812),(-298.783111572266,1267.951171875,5000.),(874.774963378906,818.52783203125,4688.61865234375),(-3164.8310546875,1859.35131835938,3901.58129882812),(-1289.18603515625,-25.3927478790283,5000.),(-613.466796875,1034.14660644531,4688.61865234375)));
#421=IFCINDEXEDPOLYGONALFACE((3,2,1));
#422=IFCINDEXEDPOLYGONALFACE((3,4,2));
#423=IFCINDEXEDPOLYGONALFACE((7,6,5));
#424=IFCINDEXEDPOLYGONALFACE((7,4,6));
#425=IFCINDEXEDPOLYGONALFACE((10,9,8));
#426=IFCINDEXEDPOLYGONALFACE((10,4,9));
#427=IFCINDEXEDPOLYGONALFACE((13,12,11));
#428=IFCINDEXEDPOLYGONALFACE((13,4,12));
#429=IFCPOLYGONALFACESET(#420,$,(#421,#422,#423,#424,#425,#426,#427,#428),$);
#430=IFCCARTESIANPOINT((0.,0.));
#431=IFCAXIS2PLACEMENT2D(#430,$);
#432=IFCCIRCLE(#431,100.);
#433=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#432);
#434=IFCCARTESIANPOINT((0.,0.,0.));
#435=IFCDIRECTION((0.,0.,1.));
#436=IFCDIRECTION((1.,0.,0.));
#437=IFCAXIS2PLACEMENT3D(#434,#435,#436);
#438=IFCDIRECTION((0.,0.,1.));
#439=IFCEXTRUDEDAREASOLID(#433,#437,#438,4658.5204646405);
#440=IFCCARTESIANPOINTLIST2D(((-2517.70166015625,-2646.30053710938,0.),(-255.675521850586,-1248.60815429688,0.),(-1133.70935058594,-349.566070556641,0.),(0.,0.,0.),(3472.91040039062,-1142.93579101562,0.),(1250.74682617188,317.302124023438,0.),(806.568603515625,-858.251220703125,0.),(1171.36364746094,3483.57202148438,0.),(-298.783111572266,1267.951171875,0.),(874.774963378906,818.52783203125,0.),(-3164.8310546875,1859.35131835938,0.),(-1289.18603515625,-25.3927478790283,0.),(-613.466796875,1034.14660644531,0.)));
#441=IFCINDEXEDPOLYCURVE(#440,(IFCLINEINDEX((4,12,11,13,4)),IFCLINEINDEX((4,2,1,3,4)),IFCLINEINDEX((4,6,5,7,4)),IFCLINEINDEX((4,9,8,10,4))),$);
#442=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#441));
#443=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#429,#439));
#444=IFCGEOGRAPHICELEMENTTYPE('0If5oJIRTAxw5EHjhL6zX$',$,'Palm Tree (5m)',$,$,$,(#449,#454),$,$,.NOTDEFINED.);
#445=IFCCARTESIANPOINT((0.,0.,0.));
#446=IFCDIRECTION((1.,0.,0.));
#447=IFCDIRECTION((0.,0.,1.));
#448=IFCAXIS2PLACEMENT3D(#445,#447,#446);
#449=IFCREPRESENTATIONMAP(#448,#443);
#450=IFCCARTESIANPOINT((0.,0.,0.));
#451=IFCDIRECTION((1.,0.,0.));
#452=IFCDIRECTION((0.,0.,1.));
#453=IFCAXIS2PLACEMENT3D(#450,#452,#451);
#454=IFCREPRESENTATIONMAP(#453,#442);
#455=IFCCARTESIANPOINTLIST3D(((-5223.76025390625,-5490.57861328125,12720.986328125),(-530.478881835938,-2590.62841796875,15000.),(-2352.23486328125,-725.284240722656,14353.9423828125),(0.,0.,14291.4931640625),(7205.64013671875,-2371.37817382812,12720.986328125),(2595.06591796875,658.342590332031,15000.),(1673.47912597656,-1780.7109375,14353.9423828125),(2430.36059570312,7227.76025390625,12720.986328125),(-619.919128417969,2630.76171875,15000.),(1814.99462890625,1698.29223632812,14353.9423828125),(-6566.43310546875,3857.80639648438,12720.986328125),(-2674.81982421875,-52.6852073669434,15000.),(-1272.82897949219,2145.66088867188,14353.9423828125)));
#456=IFCINDEXEDPOLYGONALFACE((3,2,1));
#457=IFCINDEXEDPOLYGONALFACE((3,4,2));
#458=IFCINDEXEDPOLYGONALFACE((7,6,5));
#459=IFCINDEXEDPOLYGONALFACE((7,4,6));
#460=IFCINDEXEDPOLYGONALFACE((10,9,8));
#461=IFCINDEXEDPOLYGONALFACE((10,4,9));
#462=IFCINDEXEDPOLYGONALFACE((13,12,11));
#463=IFCINDEXEDPOLYGONALFACE((13,4,12));
#464=IFCPOLYGONALFACESET(#455,$,(#456,#457,#458,#459,#460,#461,#462,#463),$);
#465=IFCCARTESIANPOINT((0.,0.));
#466=IFCAXIS2PLACEMENT2D(#465,$);
#467=IFCCIRCLE(#466,200.);
#468=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#467);
#469=IFCCARTESIANPOINT((0.,0.,0.));
#470=IFCDIRECTION((0.,0.,1.));
#471=IFCDIRECTION((1.,0.,0.));
#472=IFCAXIS2PLACEMENT3D(#469,#470,#471);
#473=IFCDIRECTION((0.,0.,1.));
#474=IFCEXTRUDEDAREASOLID(#468,#472,#473,14291.4938033876);
#475=IFCCARTESIANPOINTLIST2D(((-5223.76025390625,-5490.57861328125,0.),(-530.478881835938,-2590.62841796875,0.),(-2352.23486328125,-725.284240722656,0.),(0.,0.,0.),(7205.64013671875,-2371.37817382812,0.),(2595.06591796875,658.342590332031,0.),(1673.47912597656,-1780.7109375,0.),(2430.36059570312,7227.76025390625,0.),(-619.919128417969,2630.76171875,0.),(1814.99462890625,1698.29223632812,0.),(-6566.43310546875,3857.80639648438,0.),(-2674.81982421875,-52.6852073669434,0.),(-1272.82897949219,2145.66088867188,0.)));
#476=IFCINDEXEDPOLYCURVE(#475,(IFCLINEINDEX((4,12,11,13,4)),IFCLINEINDEX((4,2,1,3,4)),IFCLINEINDEX((4,6,5,7,4)),IFCLINEINDEX((4,9,8,10,4))),$);
#477=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#476));
#478=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#464,#474));
#479=IFCGEOGRAPHICELEMENTTYPE('11RlAtH99EAwxYuNeuU3sf',$,'Palm Tree (15m)',$,$,$,(#484,#489),$,$,.NOTDEFINED.);
#480=IFCCARTESIANPOINT((0.,0.,0.));
#481=IFCDIRECTION((1.,0.,0.));
#482=IFCDIRECTION((0.,0.,1.));
#483=IFCAXIS2PLACEMENT3D(#480,#482,#481);
#484=IFCREPRESENTATIONMAP(#483,#478);
#485=IFCCARTESIANPOINT((0.,0.,0.));
#486=IFCDIRECTION((1.,0.,0.));
#487=IFCDIRECTION((0.,0.,1.));
#488=IFCAXIS2PLACEMENT3D(#485,#487,#486);
#489=IFCREPRESENTATIONMAP(#488,#477);
#490=IFCCARTESIANPOINTLIST2D(((-117.312850952148,172.941558837891),(-151.676498413086,131.458541870117),(-144.688446044922,117.318817138672),(-174.28141784668,93.263786315918),(-184.067886352539,31.584659576416),(-129.745407104492,23.0444221496582),(-185.461486816406,18.062141418457),(-192.134033203125,-57.0443878173828),(-161.214447021484,-70.1103286743164),(-165.422088623047,-93.5437316894531),(-137.997512817383,-133.918304443359),(-124.311111450195,-135.353179931641),(-86.3092803955078,-176.496170043945),(-60.6325874328613,-180.478744506836),(-64.4376983642578,-160.752395629883),(-43.5850677490234,-190.617202758789),(73.8348922729492,-175.466888427734),(61.6634140014648,-137.027221679688),(95.5640106201172,-161.898178100586),(183.263854980469,-73.7681503295898),(165.519485473633,-58.7545623779297),(189.573257446289,-49.020824432373),(193.359359741211,16.9163608551025),(150.580032348633,10.4255018234253),(182.048736572266,38.1974563598633),(165.584594726562,110.443428039551),(132.706695556641,129.227111816406),(115.073692321777,163.402984619141),(79.5248870849609,175.583862304688),(37.4673728942871,150.271774291992),(67.6689071655273,182.186645507812),(-2.62604808807373,195.961898803711),(-37.2997703552246,188.284133911133),(-63.8644866943359,176.708084106445)));
#491=IFCINDEXEDPOLYCURVE(#490,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#492=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(117.302441515039,-1.13777512519817,58.3923179610087),(53.377571714232,105.610650925318,62.3202791033923),(-55.6244394575812,95.1611838079015,57.4735668970959),(-118.915635014047,-4.00005317301758,64.3879276891917),(-50.1350881193688,-107.884608784393,62.9054337394378),(59.731049775491,-102.491815128895,53.6807486293646),(146.906104220826,-0.69070158306711,117.259498053308),(74.642874454171,118.927684503425,118.571119308818),(-64.3347213491543,132.310244754508,116.098943414462),(-151.398496540833,-7.93511769346546,108.4292747185),(-64.9972969910001,-127.954265195564,112.144043912281),(78.4244732459604,-127.770213308726,115.069429229913),(171.029828655319,-6.96009318197039,172.781311039802),(91.5317530292571,143.505260166657,167.017354927548),(-87.4207433432292,141.593355377397,171.374227406436),(-166.965607502459,2.52625502014577,171.964311199016),(-80.3446548142891,-154.607547312916,172.504339058381),(84.0134637506361,-147.38168471864,165.235222658882),(204.408203217165,-6.45430666905036,223.233248504121),(104.919196032396,180.368183544464,227.503132612252),(-101.374706692027,169.13279077514,224.966682842878),(-198.123955664413,-5.14463342846837,222.483148640721),(-100.708242261103,-178.566075851614,230.951025870888),(105.136890789784,-168.764898526881,228.253562815018),(169.614473432866,-1.04463121608905,277.794422912835),(89.4278378793009,146.309073034627,282.825057518454),(-92.7478661479432,148.171452288475,287.039869191095),(-173.803942263847,5.91272872635847,288.487937182262),(-90.1641347976938,-148.596895890433,292.282826796631),(86.3484217758093,-147.368879572635,278.71866369527),(143.936844531015,-0.61693979525705,341.275220938245),(70.7802990636777,126.15899497738,343.475815631913),(-72.2150011926783,119.452777236545,341.9186919364),(-136.607815489692,-1.35722090851466,335.422228133748),(-80.0080465064155,-124.23333896697,335.666309926296),(65.5372278188084,-131.059931585998,342.122396142724),(0.05,0.,400.),(0.025,0.0433012701892219,400.),(-0.025,0.0433012701892219,400.),(-0.05,6.12323399573677E-18,400.),(-0.025,-0.0433012701892219,400.),(0.025,-0.0433012701892219,400.)));
#493=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#494=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#495=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#496=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#497=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#498=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#499=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#500=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#501=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#502=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#503=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#504=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#505=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#506=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#507=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#508=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#509=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#510=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#511=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#512=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#513=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#514=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#515=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#516=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#517=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#518=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#519=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#520=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#521=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#522=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#523=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#524=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#525=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#526=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#527=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#528=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#529=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#530=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#531=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#532=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#533=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#534=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#535=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#536=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#537=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#538=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#539=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#540=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#541=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#542=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#543=IFCPOLYGONALFACESET(#492,$,(#493,#494,#495,#496,#497,#498,#499,#500,#501,#502,#503,#504,#505,#506,#507,#508,#509,#510,#511,#512,#513,#514,#515,#516,#517,#518,#519,#520,#521,#522,#523,#524,#525,#526,#527,#528,#529,#530,#531,#532,#533,#534,#535,#536,#537,#538,#539,#540,#541,#542),$);
#544=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#491));
#545=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#543));
#546=IFCGEOGRAPHICELEMENTTYPE('224k6o88949Ak$WjDPqiY0',$,'Shrub Small (0.4m)',$,$,$,(#551,#556),$,$,.NOTDEFINED.);
#547=IFCCARTESIANPOINT((0.,0.,0.));
#548=IFCDIRECTION((1.,0.,0.));
#549=IFCDIRECTION((0.,0.,1.));
#550=IFCAXIS2PLACEMENT3D(#547,#549,#548);
#551=IFCREPRESENTATIONMAP(#550,#545);
#552=IFCCARTESIANPOINT((0.,0.,0.));
#553=IFCDIRECTION((1.,0.,0.));
#554=IFCDIRECTION((0.,0.,1.));
#555=IFCAXIS2PLACEMENT3D(#552,#554,#553);
#556=IFCREPRESENTATIONMAP(#555,#544);
#557=IFCCARTESIANPOINTLIST2D(((-234.625701904297,345.883117675781),(-303.352996826172,262.917083740234),(-289.376892089844,234.637634277344),(-348.562835693359,186.527572631836),(-368.135772705078,63.169319152832),(-259.490814208984,46.0888442993164),(-370.922973632812,36.1242828369141),(-384.26806640625,-114.088775634766),(-322.428894042969,-140.220657348633),(-330.844177246094,-187.087463378906),(-275.995025634766,-267.836608886719),(-248.622222900391,-270.706359863281),(-172.618560791016,-352.992340087891),(-121.265174865723,-360.957489013672),(-128.875396728516,-321.504791259766),(-87.1701354980469,-381.234405517578),(147.669784545898,-350.933776855469),(123.32682800293,-274.054443359375),(191.128021240234,-323.796356201172),(366.527709960938,-147.53630065918),(331.038970947266,-117.509124755859),(379.146514892578,-98.0416488647461),(386.718719482422,33.8327217102051),(301.160064697266,20.8510036468506),(364.097473144531,76.3949127197266),(331.169189453125,220.886856079102),(265.413391113281,258.454223632812),(230.147384643555,326.805969238281),(159.049774169922,351.167724609375),(74.9347457885742,300.543548583984),(135.337814331055,364.373291015625),(-5.25209617614746,391.923797607422),(-74.5995407104492,376.568267822266),(-127.728973388672,353.416168212891)));
#558=IFCINDEXEDPOLYCURVE(#557,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#559=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(234.604883030077,-2.27555025039633,116.784635922017),(106.755143428464,211.221301850635,124.640558206785),(-111.248878915162,190.322367615803,114.947133794192),(-237.831270028093,-8.00010634603516,128.775855378383),(-100.270176238738,-215.769217568787,125.810867478876),(119.462099550982,-204.983630257789,107.361497258729),(293.812208441652,-1.38140316613422,234.518996106616),(149.285748908342,237.85536900685,237.142238617636),(-128.669442698309,264.620489509016,232.197886828923),(-302.796993081665,-15.8702353869309,216.858549437001),(-129.994593982,-255.908530391129,224.288087824562),(156.848946491921,-255.540426617453,230.138858459826),(342.059657310639,-13.9201863639408,345.562622079605),(183.063506058514,287.010520333314,334.034709855096),(-174.841486686458,283.186710754793,342.748454812872),(-333.931215004918,5.05251004029153,343.928622398032),(-160.689309628578,-309.215094625832,345.008678116763),(168.026927501272,-294.763369437281,330.470445317765),(408.81640643433,-12.9086133381007,446.466497008241),(209.838392064792,360.736367088927,455.006265224505),(-202.749413384054,338.26558155028,449.933365685756),(-396.247911328827,-10.2892668569367,444.966297281442),(-201.416484522207,-357.132151703227,461.902051741776),(210.273781579568,-337.529797053763,456.507125630036),(339.228946865733,-2.0892624321781,555.588845825671),(178.855675758602,292.618146069253,565.650115036909),(-185.495732295886,296.34290457695,574.07973838219),(-347.607884527694,11.8254574527169,576.975874364524),(-180.328269595388,-297.193791780866,584.565653593263),(172.696843551619,-294.737759145271,557.43732739054),(287.87368906203,-1.2338795905141,682.550441876491),(141.560598127355,252.31798995476,686.951631263826),(-144.430002385357,238.90555447309,683.837383872801),(-273.215630979383,-2.71444181702932,670.844456267496),(-160.016093012831,-248.46667793394,671.332619852593),(131.074455637617,-262.119863171996,684.244792285448),(0.05,0.,800.),(0.025,0.0433012701892219,800.),(-0.025,0.0433012701892219,800.),(-0.05,6.12323399573677E-18,800.),(-0.025,-0.0433012701892219,800.),(0.025,-0.0433012701892219,800.)));
#560=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#561=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#562=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#563=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#564=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#565=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#566=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#567=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#568=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#569=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#570=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#571=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#572=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#573=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#574=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#575=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#576=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#577=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#578=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#579=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#580=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#581=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#582=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#583=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#584=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#585=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#586=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#587=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#588=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#589=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#590=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#591=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#592=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#593=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#594=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#595=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#596=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#597=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#598=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#599=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#600=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#601=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#602=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#603=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#604=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#605=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#606=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#607=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#608=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#609=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#610=IFCPOLYGONALFACESET(#559,$,(#560,#561,#562,#563,#564,#565,#566,#567,#568,#569,#570,#571,#572,#573,#574,#575,#576,#577,#578,#579,#580,#581,#582,#583,#584,#585,#586,#587,#588,#589,#590,#591,#592,#593,#594,#595,#596,#597,#598,#599,#600,#601,#602,#603,#604,#605,#606,#607,#608,#609),$);
#611=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#558));
#612=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#610));
#613=IFCGEOGRAPHICELEMENTTYPE('0sCZ5iWS904ODo2Mqo8nHu',$,'Shrum Medium (0.8m)',$,$,$,(#618,#623),$,$,.NOTDEFINED.);
#614=IFCCARTESIANPOINT((0.,0.,0.));
#615=IFCDIRECTION((1.,0.,0.));
#616=IFCDIRECTION((0.,0.,1.));
#617=IFCAXIS2PLACEMENT3D(#614,#616,#615);
#618=IFCREPRESENTATIONMAP(#617,#612);
#619=IFCCARTESIANPOINT((0.,0.,0.));
#620=IFCDIRECTION((1.,0.,0.));
#621=IFCDIRECTION((0.,0.,1.));
#622=IFCAXIS2PLACEMENT3D(#619,#621,#620);
#623=IFCREPRESENTATIONMAP(#622,#611);
#624=IFCCARTESIANPOINTLIST2D(((-527.907836914062,778.237060546875),(-682.544250488281,591.5634765625),(-651.098022460938,527.934692382812),(-784.266357421875,419.687042236328),(-828.305480957031,142.130966186523),(-583.854309082031,103.699897766113),(-834.57666015625,81.2796401977539),(-864.603149414062,-256.699737548828),(-725.465026855469,-315.496459960938),(-744.3994140625,-420.946807861328),(-620.988830566406,-602.632385253906),(-559.400024414062,-609.08935546875),(-388.391754150391,-794.232788085938),(-272.846649169922,-812.154357910156),(-289.969635009766,-723.3857421875),(-196.1328125,-857.777404785156),(332.257019042969,-789.601013183594),(277.4853515625,-616.622497558594),(430.038055419922,-728.541809082031),(824.687377929688,-331.956665039062),(744.837707519531,-264.395538330078),(853.079650878906,-220.593704223633),(870.117126464844,76.1236267089844),(677.610168457031,46.9147605895996),(819.219299316406,171.888565063477),(745.130676269531,496.995422363281),(597.18017578125,581.522033691406),(517.831604003906,735.313415527344),(357.861999511719,790.127380371094),(168.603179931641,676.222961425781),(304.510101318359,819.839904785156),(-11.8172159194946,881.828552246094),(-167.848968505859,847.278625488281),(-287.390197753906,795.186340332031)));
#625=IFCINDEXEDPOLYCURVE(#624,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#626=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(527.860986817674,-5.11998806339175,262.765430824539),(240.199072714044,475.247929163929,280.441255965265),(-250.309977559115,428.225327135557,258.631051036932),(-535.120357563209,-18.0002392785791,289.745674601363),(-225.607896537159,-485.480739529771,283.07445182747),(268.789723989709,-461.213168080025,241.563368832141),(661.077468993717,-3.10815712380199,527.667741239885),(335.892935043769,535.174580265412,533.570036889682),(-289.506246071194,595.396101395287,522.445245365077),(-681.293234433747,-35.7080296205946,487.931736233252),(-292.4878364595,-575.794193380039,504.648197605265),(352.910129606822,-574.965959889268,517.812431534608),(769.634228948937,-31.3204193188668,777.515899679111),(411.892888631657,645.773670749957,751.578097173967),(-393.393345044531,637.170099198285,771.184023328963),(-751.345233761067,11.3681475906559,773.839400395571),(-361.550946664301,-695.733962908123,776.269525762717),(378.060586877863,-663.217581233882,743.558501964971),(919.836914477244,-29.0443800107266,1004.54961826854),(472.136382145783,811.656825950086,1023.76409675514),(-456.186180114122,761.097558488129,1012.35007279295),(-891.55780048986,-23.1508504281077,1001.17416888324),(-453.187090174966,-803.547341332261,1039.279616419),(473.116008554028,-759.442043370966,1027.14103266758),(763.265130447899,-4.70084047240072,1250.07490310776),(402.425270456854,658.39082865582,1272.71275883304),(-417.365397665745,666.771535298137,1291.67941135993),(-782.117740187312,26.6072792686131,1298.19571732018),(-405.738606589622,-668.686031506949,1315.27272058484),(388.567897991142,-663.159958076859,1254.23398662872),(647.715800389567,-2.77622907865673,1535.7384942221),(318.51134578655,567.715477398209,1545.64117034361),(-324.967505367052,537.537497564452,1538.6341137138),(-614.735169703612,-6.10749408831597,1509.40002660187),(-360.03620927887,-559.050025351365,1510.49839466833),(294.917525184638,-589.769692136991,1539.55078264226),(0.05,0.,1800.),(0.025,0.0433012701892219,1800.),(-0.025,0.0433012701892219,1800.),(-0.05,6.12323399573677E-18,1800.),(-0.025,-0.0433012701892219,1800.),(0.025,-0.0433012701892219,1800.)));
#627=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#628=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#629=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#630=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#631=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#632=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#633=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#634=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#635=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#636=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#637=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#638=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#639=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#640=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#641=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#642=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#643=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#644=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#645=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#646=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#647=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#648=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#649=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#650=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#651=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#652=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#653=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#654=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#655=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#656=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#657=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#658=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#659=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#660=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#661=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#662=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#663=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#664=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#665=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#666=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#667=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#668=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#669=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#670=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#671=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#672=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#673=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#674=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#675=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#676=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#677=IFCPOLYGONALFACESET(#626,$,(#627,#628,#629,#630,#631,#632,#633,#634,#635,#636,#637,#638,#639,#640,#641,#642,#643,#644,#645,#646,#647,#648,#649,#650,#651,#652,#653,#654,#655,#656,#657,#658,#659,#660,#661,#662,#663,#664,#665,#666,#667,#668,#669,#670,#671,#672,#673,#674,#675,#676),$);
#678=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#625));
#679=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#677));
#680=IFCGEOGRAPHICELEMENTTYPE('3mKZtHjt12Rh_uInKdrcGZ',$,'Shrub Big (1.8m)',$,$,$,(#685,#690),$,$,.NOTDEFINED.);
#681=IFCCARTESIANPOINT((0.,0.,0.));
#682=IFCDIRECTION((1.,0.,0.));
#683=IFCDIRECTION((0.,0.,1.));
#684=IFCAXIS2PLACEMENT3D(#681,#683,#682);
#685=IFCREPRESENTATIONMAP(#684,#679);
#686=IFCCARTESIANPOINT((0.,0.,0.));
#687=IFCDIRECTION((1.,0.,0.));
#688=IFCDIRECTION((0.,0.,1.));
#689=IFCAXIS2PLACEMENT3D(#686,#688,#687);
#690=IFCREPRESENTATIONMAP(#689,#678);
#691=IFCCARTESIANPOINT((0.,0.));
#692=IFCAXIS2PLACEMENT2D(#691,$);
#693=IFCCIRCLE(#692,100.);
#694=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#693);
#695=IFCCARTESIANPOINT((0.,0.,0.));
#696=IFCDIRECTION((0.,0.,1.));
#697=IFCDIRECTION((1.,0.,0.));
#698=IFCAXIS2PLACEMENT3D(#695,#696,#697);
#699=IFCDIRECTION((0.,0.,1.));
#700=IFCEXTRUDEDAREASOLID(#694,#698,#699,460.);
#701=IFCCARTESIANPOINT((0.,0.,1130.));
#702=IFCDIRECTION((0.,0.,1.));
#703=IFCDIRECTION((1.,0.,0.));
#704=IFCAXIS2PLACEMENT3D(#701,#702,#703);
#705=IFCSPHERE(#704,670.);
#706=IFCCARTESIANPOINT((0.,0.));
#707=IFCAXIS2PLACEMENT2D(#706,$);
#708=IFCCIRCLE(#707,670.);
#709=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#708));
#710=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#700,#705));
#711=IFCGEOGRAPHICELEMENTTYPE('24b7xpbZb38f1BXogqUXhD',$,'Simple Tree (1.8m)',$,$,$,(#716,#721),$,$,.NOTDEFINED.);
#712=IFCCARTESIANPOINT((0.,0.,0.));
#713=IFCDIRECTION((1.,0.,0.));
#714=IFCDIRECTION((0.,0.,1.));
#715=IFCAXIS2PLACEMENT3D(#712,#714,#713);
#716=IFCREPRESENTATIONMAP(#715,#710);
#717=IFCCARTESIANPOINT((0.,0.,0.));
#718=IFCDIRECTION((1.,0.,0.));
#719=IFCDIRECTION((0.,0.,1.));
#720=IFCAXIS2PLACEMENT3D(#717,#719,#718);
#721=IFCREPRESENTATIONMAP(#720,#709);
#722=IFCCARTESIANPOINT((0.,0.));
#723=IFCAXIS2PLACEMENT2D(#722,$);
#724=IFCCIRCLE(#723,100.);
#725=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#724);
#726=IFCCARTESIANPOINT((0.,0.,0.));
#727=IFCDIRECTION((0.,0.,1.));
#728=IFCDIRECTION((1.,0.,0.));
#729=IFCAXIS2PLACEMENT3D(#726,#727,#728);
#730=IFCDIRECTION((0.,0.,1.));
#731=IFCEXTRUDEDAREASOLID(#725,#729,#730,1710.);
#732=IFCCARTESIANPOINT((0.,0.,3355.));
#733=IFCDIRECTION((0.,0.,1.));
#734=IFCDIRECTION((1.,0.,0.));
#735=IFCAXIS2PLACEMENT3D(#732,#733,#734);
#736=IFCSPHERE(#735,1645.);
#737=IFCCARTESIANPOINT((0.,0.));
#738=IFCAXIS2PLACEMENT2D(#737,$);
#739=IFCCIRCLE(#738,1645.);
#740=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#739));
#741=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#731,#736));
#742=IFCGEOGRAPHICELEMENTTYPE('3VL8Zl9Xb2AwPSDD7jujfl',$,'Simple Tree (5m)',$,$,$,(#747,#752),$,$,.NOTDEFINED.);
#743=IFCCARTESIANPOINT((0.,0.,0.));
#744=IFCDIRECTION((1.,0.,0.));
#745=IFCDIRECTION((0.,0.,1.));
#746=IFCAXIS2PLACEMENT3D(#743,#745,#744);
#747=IFCREPRESENTATIONMAP(#746,#741);
#748=IFCCARTESIANPOINT((0.,0.,0.));
#749=IFCDIRECTION((1.,0.,0.));
#750=IFCDIRECTION((0.,0.,1.));
#751=IFCAXIS2PLACEMENT3D(#748,#750,#749);
#752=IFCREPRESENTATIONMAP(#751,#740);
#753=IFCCARTESIANPOINT((0.,0.));
#754=IFCAXIS2PLACEMENT2D(#753,$);
#755=IFCCIRCLE(#754,220.);
#756=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#755);
#757=IFCCARTESIANPOINT((0.,0.,0.));
#758=IFCDIRECTION((0.,0.,1.));
#759=IFCDIRECTION((1.,0.,0.));
#760=IFCAXIS2PLACEMENT3D(#757,#758,#759);
#761=IFCDIRECTION((0.,0.,1.));
#762=IFCEXTRUDEDAREASOLID(#756,#760,#761,5790.);
#763=IFCCARTESIANPOINT((0.,0.,10395.));
#764=IFCDIRECTION((0.,0.,1.));
#765=IFCDIRECTION((1.,0.,0.));
#766=IFCAXIS2PLACEMENT3D(#763,#764,#765);
#767=IFCSPHERE(#766,4605.);
#768=IFCCARTESIANPOINT((0.,0.));
#769=IFCAXIS2PLACEMENT2D(#768,$);
#770=IFCCIRCLE(#769,4605.);
#771=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#770));
#772=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#762,#767));
#773=IFCGEOGRAPHICELEMENTTYPE('3jGYIuJcL0phM2h4r9r95Q',$,'Simple Tree (15m)',$,$,$,(#778,#783),$,$,.NOTDEFINED.);
#774=IFCCARTESIANPOINT((0.,0.,0.));
#775=IFCDIRECTION((1.,0.,0.));
#776=IFCDIRECTION((0.,0.,1.));
#777=IFCAXIS2PLACEMENT3D(#774,#776,#775);
#778=IFCREPRESENTATIONMAP(#777,#772);
#779=IFCCARTESIANPOINT((0.,0.,0.));
#780=IFCDIRECTION((1.,0.,0.));
#781=IFCDIRECTION((0.,0.,1.));
#782=IFCAXIS2PLACEMENT3D(#779,#781,#780);
#783=IFCREPRESENTATIONMAP(#782,#771);
#784=IFCCARTESIANPOINTLIST2D(((-498.579620361328,735.001647949219),(-644.625122070312,558.698791503906),(-614.925903320312,498.60498046875),(-740.696044921875,396.37109375),(-782.288513183594,134.234802246094),(-551.41796875,97.9387969970703),(-788.211303710938,76.7640991210938),(-816.569641113281,-242.43864440918),(-685.161376953125,-297.968902587891),(-703.043884277344,-397.560852050781),(-586.489440917969,-569.15283203125),(-528.322204589844,-575.251037597656),(-366.814422607422,-750.108703613281),(-257.688507080078,-767.03466796875),(-273.860229492188,-683.197692871094),(-185.236541748047,-810.123107910156),(313.798278808594,-745.734313964844),(262.069519042969,-582.365661621094),(406.147064208984,-688.067260742188),(778.871398925781,-313.5146484375),(703.457824707031,-249.706893920898),(805.686340332031,-208.338500976562),(821.777282714844,71.8945388793945),(639.965148925781,44.3083839416504),(773.707153320312,162.339202880859),(703.734558105469,469.384552001953),(564.003479003906,549.215209960938),(489.063201904297,694.462707519531),(337.980773925781,746.2314453125),(159.236328125,638.655029296875),(287.592864990234,774.293273925781),(-11.1607036590576,832.838073730469),(-158.524017333984,800.207580566406),(-271.424072265625,751.009338378906)));
#785=IFCINDEXEDPOLYCURVE(#784,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#786=IFCCARTESIANPOINTLIST3D(((80.,0.,0.),(40.,69.2820323027551,0.),(-40.,69.2820323027551,0.),(-80.,9.79717439317883E-15,0.),(-40.,-69.2820323027551,0.),(40.,-69.2820323027551,0.),(80.,0.,280.),(40.,69.2820323027551,280.),(-40.,69.2820323027551,280.),(-80.,9.79717439317883E-15,280.),(-40.,-69.2820323027551,280.),(40.,-69.2820323027551,280.),(610.340986817674,-5.11998806339175,502.765430824539),(281.439072714044,546.677704468069,520.441255965265),(-291.549977559115,499.655102439697,498.631051036932),(-617.600357563209,-18.0002392785791,529.745674601363),(-266.847896537159,-556.910514833911,523.07445182747),(310.029723989709,-532.642943384166,481.563368832141),(699.397468993717,-3.10815712380199,727.667741239885),(355.052935043769,568.360673738432,733.570036889682),(-308.666246071194,628.582194868307,722.445245365077),(-719.613234433747,-35.7080296205946,687.931736233252),(-311.6478364595,-608.980286853059,704.648197605265),(372.070129606822,-608.152053362288,717.812431534607),(763.794228948937,-31.3204193188668,937.51589967911),(408.972888631657,640.716082391856,911.578097173966),(-390.473345044531,632.112510840184,931.184023328963),(-745.505233761067,11.3681475906559,933.839400395571),(-358.630946664301,-690.676374550022,936.269525762716),(375.140586877863,-658.159992875781,903.558501964971),(869.836914477244,-29.0443800107266,1124.54961826854),(447.136382145783,768.355555760864,1143.76409675514),(-431.186180114122,717.796288298907,1132.35007279295),(-841.55780048986,-23.1508504281077,1121.17416888324),(-428.187090174966,-760.246071143039,1159.279616419),(448.116008554028,-716.140773181744,1147.14103266758),(757.425130447899,-4.70084047240072,1330.07490310776),(399.505270456854,653.333240297718,1352.71275883304),(-414.445397665745,661.713946940036,1371.67941135993),(-776.277740187312,26.6072792686131,1378.19571732018),(-402.818606589622,-663.628443148848,1395.27272058484),(385.647897991142,-658.102369718758,1334.23398662872),(686.035800389567,-2.77622907865673,1575.7384942221),(337.67134578655,600.901570871229,1585.64117034361),(-344.127505367052,570.723591037471,1578.6341137138),(-653.055169703612,-6.10749408831596,1549.40002660187),(-379.19620927887,-592.236118824385,1550.49839466833),(314.077525184638,-622.955785610011,1579.55078264226),(0.05,0.,1800.),(0.025,0.0433012701892219,1800.),(-0.025,0.0433012701892219,1800.),(-0.05,6.12323399573677E-18,1800.),(-0.025,-0.0433012701892219,1800.),(0.025,-0.0433012701892219,1800.)));
#787=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#788=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#789=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#790=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#791=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#792=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#793=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#794=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#795=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#796=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#797=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#798=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#799=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#800=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#801=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#802=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#803=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#804=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#805=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#806=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#807=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#808=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#809=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#810=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#811=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#812=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#813=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#814=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#815=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#816=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#817=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#818=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#819=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#820=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#821=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#822=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#823=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#824=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#825=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#826=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#827=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#828=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#829=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#830=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#831=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#832=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#833=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#834=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#835=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#836=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#837=IFCPOLYGONALFACESET(#786,$,(#787,#788,#789,#790,#791,#792,#793,#794,#795,#796,#797,#798,#799,#800,#801,#802,#803,#804,#805,#806,#807,#808,#809,#810,#811,#812,#813,#814,#815,#816,#817,#818,#819,#820,#821,#822,#823,#824,#825,#826,#827,#828,#829,#830,#831,#832,#833,#834,#835,#836),$);
#838=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#785));
#839=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#837));
#840=IFCGEOGRAPHICELEMENTTYPE('1CLHhCfcnFaBY1EM4kLSOR',$,'Tree Small (1.8m)',$,$,$,(#845,#850),$,$,.NOTDEFINED.);
#841=IFCCARTESIANPOINT((0.,0.,0.));
#842=IFCDIRECTION((1.,0.,0.));
#843=IFCDIRECTION((0.,0.,1.));
#844=IFCAXIS2PLACEMENT3D(#841,#843,#842);
#845=IFCREPRESENTATIONMAP(#844,#839);
#846=IFCCARTESIANPOINT((0.,0.,0.));
#847=IFCDIRECTION((1.,0.,0.));
#848=IFCDIRECTION((0.,0.,1.));
#849=IFCAXIS2PLACEMENT3D(#846,#848,#847);
#850=IFCREPRESENTATIONMAP(#849,#838);
#851=IFCCARTESIANPOINTLIST2D(((-2932.8212890625,4323.5390625),(-3791.91259765625,3286.46362304688),(-3617.21118164062,2932.97045898438),(-4357.03564453125,2331.5947265625),(-4601.697265625,789.616455078125),(-3243.63500976562,576.110534667969),(-4636.537109375,451.553527832031),(-4803.35107421875,-1426.10961914062),(-4030.36108398438,-1752.75817871094),(-4135.55224609375,-2338.59326171875),(-3449.93798828125,-3347.95776367188),(-3107.77783203125,-3383.82958984375),(-2157.73193359375,-4412.404296875),(-1515.81469726562,-4511.96826171875),(-1610.94250488281,-4018.80981445312),(-1089.62670898438,-4765.43017578125),(1845.87219238281,-4386.67236328125),(1541.58532714844,-3425.68041992188),(2389.10034179688,-4047.45458984375),(4581.5966796875,-1844.20373535156),(4137.9873046875,-1468.86413574219),(4739.33154296875,-1225.52062988281),(4833.98388671875,422.909027099609),(3764.5009765625,260.637542724609),(4551.21826171875,954.936462402344),(4139.615234375,2761.08569335938),(3317.66748046875,3230.677734375),(2876.84228515625,4085.07470703125),(1988.12219238281,4389.5966796875),(936.684326171875,3756.79443359375),(1691.72277832031,4554.66650390625),(-65.6511993408203,4899.0478515625),(-932.494262695312,4707.103515625),(-1596.61218261719,4417.7021484375)));
#852=IFCINDEXEDPOLYCURVE(#851,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#853=IFCCARTESIANPOINTLIST3D(((220.,0.,0.),(110.,190.525588832576,0.),(-110.,190.525588832577,0.),(-220.,2.69422295812418E-14,0.),(-110.,-190.525588832576,0.),(110.,-190.525588832576,0.),(220.,0.,1830.),(110.,190.525588832576,1830.),(-110.,190.525588832577,1830.),(-220.,2.69422295812418E-14,1830.),(-110.,-190.525588832576,1830.),(110.,-190.525588832576,1830.),(3602.84155681395,-42.6665671949312,3758.28335210925),(1603.6589392837,3271.04318828699,3905.58189494864),(-1687.91647965929,2879.18817138389,3723.83018721253),(-3663.33631302674,-150.001993988159,3983.11871691612),(-1482.06580447633,-3356.31660800234,3927.52519380035),(1841.91436658091,-3154.08684592113,3581.5995021726),(4144.97890828097,-25.9013093650166,5704.3740341419),(2117.10779203141,3278.52951811646,5753.55983122354),(-1730.55205059328,3780.37552753208,5660.85323518517),(-4313.44362028123,-297.566913504955,5373.24065908662),(-1755.3986371625,-3617.02629407169,5512.5445038534),(2258.91774672351,-3610.12434831526,5622.24645326459),(4481.61857457447,-261.00349432389,7525.01344970687),(2466.44073859714,3708.28617613811,7308.86509549734),(-2312.27787537109,3636.58974654084,7472.24781345564),(-4329.21028134222,94.734563255466,7494.37595567738),(-2046.92455553584,-4124.62194412282,7514.62700040359),(2184.50489064885,-3853.65209683748,7242.03513542238),(5165.3076206437,-242.036500089388,9155.53253319023),(2684.46985121485,4598.74337345629,9315.65318724518),(-2551.55150095102,4177.41614460665,9220.53632089363),(-4929.6483374155,-192.923753567564,9127.40378831275),(-2526.55908479138,-4531.16433497441,9444.94918444402),(2692.6334046169,-4163.62018529695,9343.7943198489),(4428.54275373249,-39.1736706033394,10940.1480020885),(2387.54392047378,3813.42915868696,11128.7967997992),(-2512.04498054787,3883.26838070627,11286.8522375232),(-4585.64783489427,221.727327238442,11341.154787192),(-2415.15505491352,-3899.22251577971,11483.4631477308),(2272.06581659285,-3853.17190386229,10974.8070314298),(4033.63166991306,-23.1352423221394,13059.2493566128),(1972.26121488791,3549.70366088977,13141.7716576253),(-2026.06254472544,3298.22049560846,13083.3795190436),(-3758.79308086343,-50.8957840692999,12839.7621264441),(-2318.30174399058,-3477.4915604994,12848.9151936647),(1775.64604320532,-3733.48878371295,13091.0184267807),(0.05,0.,15000.),(0.025,0.0433012701892219,15000.),(-0.025,0.0433012701892219,15000.),(-0.05,6.12323399573677E-18,15000.),(-0.025,-0.0433012701892219,15000.),(0.025,-0.0433012701892219,15000.)));
#854=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#855=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#856=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#857=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#858=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#859=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#860=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#861=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#862=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#863=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#864=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#865=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#866=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#867=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#868=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#869=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#870=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#871=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#872=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#873=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#874=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#875=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#876=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#877=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#878=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#879=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#880=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#881=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#882=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#883=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#884=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#885=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#886=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#887=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#888=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#889=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#890=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#891=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#892=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#893=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#894=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#895=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#896=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#897=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#898=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#899=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#900=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#901=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#902=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#903=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#904=IFCPOLYGONALFACESET(#853,$,(#854,#855,#856,#857,#858,#859,#860,#861,#862,#863,#864,#865,#866,#867,#868,#869,#870,#871,#872,#873,#874,#875,#876,#877,#878,#879,#880,#881,#882,#883,#884,#885,#886,#887,#888,#889,#890,#891,#892,#893,#894,#895,#896,#897,#898,#899,#900,#901,#902,#903),$);
#905=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#852));
#906=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#904));
#907=IFCGEOGRAPHICELEMENTTYPE('1$Hd6qXnz8ff4y_T2Agko8',$,'Tree Big (15m)',$,$,$,(#912,#917),$,$,.NOTDEFINED.);
#908=IFCCARTESIANPOINT((0.,0.,0.));
#909=IFCDIRECTION((1.,0.,0.));
#910=IFCDIRECTION((0.,0.,1.));
#911=IFCAXIS2PLACEMENT3D(#908,#910,#909);
#912=IFCREPRESENTATIONMAP(#911,#906);
#913=IFCCARTESIANPOINT((0.,0.,0.));
#914=IFCDIRECTION((1.,0.,0.));
#915=IFCDIRECTION((0.,0.,1.));
#916=IFCAXIS2PLACEMENT3D(#913,#915,#914);
#917=IFCREPRESENTATIONMAP(#916,#905);
#918=IFCCARTESIANPOINTLIST2D(((-1466.41064453125,2161.76953125),(-1895.95629882812,1643.23181152344),(-1808.60559082031,1466.48522949219),(-2178.51782226562,1165.79736328125),(-2300.8486328125,394.808227539062),(-1621.81750488281,288.055267333984),(-2318.2685546875,225.776763916016),(-2401.67553710938,-713.054809570312),(-2015.18054199219,-876.379089355469),(-2067.77612304688,-1169.29663085938),(-1724.96899414062,-1673.97888183594),(-1553.88891601562,-1691.91479492188),(-1078.86596679688,-2206.2021484375),(-757.907348632812,-2255.98413085938),(-805.471252441406,-2009.40490722656),(-544.813354492188,-2382.71508789062),(922.936096191406,-2193.33618164062),(770.792663574219,-1712.84020996094),(1194.55017089844,-2023.72729492188),(2290.79833984375,-922.101867675781),(2068.99365234375,-734.432067871094),(2369.66577148438,-612.760314941406),(2416.99194335938,211.454513549805),(1882.25048828125,130.318771362305),(2275.60913085938,477.468231201172),(2069.8076171875,1380.54284667969),(1658.83374023438,1615.3388671875),(1438.42114257812,2042.53735351562),(994.061096191406,2194.79833984375),(468.342163085938,1878.39721679688),(845.861389160156,2277.33325195312),(-32.8255996704102,2449.52392578125),(-466.247131347656,2353.5517578125),(-798.306091308594,2208.85107421875)));
#919=IFCINDEXEDPOLYCURVE(#918,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
#920=IFCCARTESIANPOINTLIST3D(((110.,0.,0.),(55.,95.2627944162882,0.),(-55.,95.2627944162883,0.),(-110.,1.34711147906209E-14,0.),(-55.,-95.2627944162882,0.),(55.,-95.2627944162882,0.),(110.,0.,840.),(55.,95.2627944162882,840.),(-55.,95.2627944162883,840.),(-110.,1.34711147906209E-14,840.),(-55.,-95.2627944162882,840.),(55.,-95.2627944162882,840.),(1794.28051893798,-14.2221890649771,1449.90397451261),(831.219646427901,1604.18946900776,1499.0034887924),(-859.305493219764,1473.57113004006,1438.4195862137),(-1814.44543767558,-50.0006646627197,1524.8490961149),(-790.68860149211,-1632.61394224621,1506.31792174297),(910.638122193637,-1565.20402155248,1391.00935786706),(2054.99296942699,-8.63376978833887,2065.74372566635),(1042.36926401047,1675.96694458701,2082.13899136023),(-913.517350197761,1843.24894772555,2051.23679268077),(-2111.14787342708,-99.1889711683183,1955.36593398126),(-921.799545720834,-1788.79920323875,2001.80054890351),(1089.63924890784,-1786.49855465328,2038.36786537391),(2247.20619152482,-87.0011647746299,2639.76638799753),(1198.81357953238,1888.50119623031,2567.71693659435),(-1147.42595845703,1864.60238636456,2622.17784258045),(-2196.40342711407,31.5781877518221,2629.5538899877),(-1058.97485184528,-2027.27978555855,2636.30423822977),(1104.83496354962,-1936.9565031301,2545.44028323603),(2555.10254021457,-80.6788333631295,3150.41560630151),(1311.48995040495,2254.60229430579,3203.78915765315),(-1267.18383365034,2114.15988468925,3172.08353553597),(-2476.54944580517,-64.3079178558546,3141.03935800901),(-1258.85302826379,-2232.07594814517,3246.8878233861),(1314.2111348723,-2109.56123158602,3213.16953518773),(2229.51425124416,-13.0578902011131,3712.43028641044),(1172.51464015793,1923.54885707993,3775.31321898068),(-1214.01499351596,1946.82859775303,3827.99836488869),(-2281.88261163142,73.9091090794808,3846.09921477827),(-1181.71835163784,-1952.14664277751,3893.53533495789),(1134.02193886428,-1936.79643880504,3723.98329619088),(2017.87722330435,-7.71174744071313,4385.94026172807),(994.087071629305,1766.35832551144,4413.44769539892),(-1012.02084824181,1682.53060375101,4393.983649205),(-1926.26436028781,-16.9652613564332,4312.77785167185),(-1109.43391466353,-1742.28762538132,4315.82887407871),(928.548681068438,-1827.62003311917,4396.52995178405),(0.05,0.,5000.),(0.025,0.0433012701892219,5000.),(-0.025,0.0433012701892219,5000.),(-0.05,6.12323399573677E-18,5000.),(-0.025,-0.0433012701892219,5000.),(0.025,-0.0433012701892219,5000.)));
#921=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
#922=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
#923=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
#924=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
#925=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
#926=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
#927=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
#928=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
#929=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
#930=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
#931=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
#932=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
#933=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
#934=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
#935=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
#936=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
#937=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
#938=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
#939=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
#940=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
#941=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
#942=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
#943=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
#944=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
#945=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
#946=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
#947=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
#948=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
#949=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
#950=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
#951=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
#952=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
#953=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
#954=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
#955=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
#956=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
#957=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
#958=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
#959=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
#960=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
#961=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
#962=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
#963=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
#964=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
#965=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
#966=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
#967=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
#968=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
#969=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
#970=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
#971=IFCPOLYGONALFACESET(#920,$,(#921,#922,#923,#924,#925,#926,#927,#928,#929,#930,#931,#932,#933,#934,#935,#936,#937,#938,#939,#940,#941,#942,#943,#944,#945,#946,#947,#948,#949,#950,#951,#952,#953,#954,#955,#956,#957,#958,#959,#960,#961,#962,#963,#964,#965,#966,#967,#968,#969,#970),$);
#972=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#919));
#973=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#971));
#974=IFCGEOGRAPHICELEMENTTYPE('1t393Epk10ahdDnhnFR8sr',$,'Tree Medium (5m)',$,$,$,(#979,#984),$,$,.NOTDEFINED.);
#975=IFCCARTESIANPOINT((0.,0.,0.));
#976=IFCDIRECTION((1.,0.,0.));
#977=IFCDIRECTION((0.,0.,1.));
#978=IFCAXIS2PLACEMENT3D(#975,#977,#976);
#979=IFCREPRESENTATIONMAP(#978,#973);
#980=IFCCARTESIANPOINT((0.,0.,0.));
#981=IFCDIRECTION((1.,0.,0.));
#982=IFCDIRECTION((0.,0.,1.));
#983=IFCAXIS2PLACEMENT3D(#980,#982,#981);
#984=IFCREPRESENTATIONMAP(#983,#972);
ENDSEC;
END-ISO-10303-21;
@@ -0,0 +1,23 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1');
FILE_NAME('','2023-09-28T23:00:50',(),(),'IfcOpenShell v0.7.0-fbd8ea1ed','IfcOpenShell v0.7.0-fbd8ea1ed','');
FILE_SCHEMA(('IFC4'));
ENDSEC;
DATA;
#1=IFCPROPERTYSETTEMPLATE('1TLQmgUKf0I8Zi07bm9Jqn',$,'ePSet_ProjectedCRS','',.PSET_OCCURRENCEDRIVEN.,'IfcProject',(#2,#3,#4,#5,#6,#7));
#2=IFCSIMPLEPROPERTYTEMPLATE('2cH53PtVT3v88uf_uGFblG',$,'Name','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
#3=IFCSIMPLEPROPERTYTEMPLATE('3JsReA6vXDqR7aNC$haRYW',$,'Description','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
#4=IFCSIMPLEPROPERTYTEMPLATE('0u0uEsT5HFtuX5GvozO9ba',$,'GeodeticDatum','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
#5=IFCSIMPLEPROPERTYTEMPLATE('1JgEX9Fsf0$ggxYltdkqiY',$,'VerticalDatum','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
#6=IFCSIMPLEPROPERTYTEMPLATE('3ahTZjYrD0MAOo5IH6QuGH',$,'MapProjection','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
#7=IFCSIMPLEPROPERTYTEMPLATE('3hqJR2ghD0GAti7q4sXKj7',$,'MapZone','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
#8=IFCPROPERTYSETTEMPLATE('1jGHTycOj0vA8xHfRl4TNs',$,'ePSet_MapConversion','',.PSET_OCCURRENCEDRIVEN.,'IfcProject',(#9,#10,#11,#12,#13,#15));
#9=IFCSIMPLEPROPERTYTEMPLATE('0nxsULXo17JRrAvNteYtNR',$,'Eastings','',.P_SINGLEVALUE.,'IfcLengthMeasure',$,$,$,$,$,.READWRITE.);
#10=IFCSIMPLEPROPERTYTEMPLATE('26RfaGJs5CqemN0Xin12XL',$,'Northings','',.P_SINGLEVALUE.,'IfcLengthMeasure',$,$,$,$,$,.READWRITE.);
#11=IFCSIMPLEPROPERTYTEMPLATE('0ziCn3nZv3m850VEUwWH42',$,'OrthogonalHeight','',.P_SINGLEVALUE.,'IfcLengthMeasure',$,$,$,$,$,.READWRITE.);
#12=IFCSIMPLEPROPERTYTEMPLATE('3d4BOt4In8WR119ms1SaAe',$,'XAxisAbscissa','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
#13=IFCSIMPLEPROPERTYTEMPLATE('1Q4Voqj2j84RQRI8l67m28',$,'XAxisOrdinate','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
#15=IFCSIMPLEPROPERTYTEMPLATE('0O1Hc0$XnDNOG_jPBmbW5r',$,'Scale','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
ENDSEC;
END-ISO-10303-21;
+71 -103
View File
@@ -21,6 +21,7 @@ import bpy
import json
import addon_utils
import ifcopenshell.api.owner.settings
import blenderbim.bim
import blenderbim.tool as tool
import blenderbim.core.owner as core_owner
from bpy.app.handlers import persistent
@@ -59,6 +60,10 @@ def name_callback(obj, data):
if not obj.BIMObjectProperties.ifc_definition_id:
return
if obj.BIMObjectProperties.is_renaming:
obj.BIMObjectProperties.is_renaming = False
return
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
if "/" in obj.name:
object_name = obj.name
@@ -177,30 +182,20 @@ def refresh_ui_data():
except AttributeError:
pass
if isinstance(tool.Ifc.get(), ifcopenshell.sqlite):
tool.Ifc.get().clear_cache()
def purge_module_data():
from blenderbim.bim import modules
refresh_ui_data()
for name, value in modules.items():
try:
getattr(getattr(getattr(ifcopenshell.api, name), "data"), "Data").purge()
except AttributeError:
pass
# TODO: deprecate prop purge functions and refactor into data classes.
try:
getattr(value, "prop").purge()
except AttributeError:
pass
if isinstance(tool.Ifc.get(), ifcopenshell.sqlite):
tool.Ifc.get().clear_cache()
@persistent
def loadIfcStore(scene):
IfcStore.purge()
purge_module_data()
refresh_ui_data()
if not IfcStore.get_file():
return
IfcStore.get_schema()
@@ -212,7 +207,7 @@ def undo_post(scene):
if IfcStore.last_transaction != bpy.context.scene.BIMProperties.last_transaction:
IfcStore.last_transaction = bpy.context.scene.BIMProperties.last_transaction
IfcStore.undo(until_key=bpy.context.scene.BIMProperties.last_transaction)
purge_module_data()
refresh_ui_data()
tool.Ifc.rebuild_element_maps()
@@ -221,7 +216,7 @@ def redo_post(scene):
if IfcStore.last_transaction != bpy.context.scene.BIMProperties.last_transaction:
IfcStore.last_transaction = bpy.context.scene.BIMProperties.last_transaction
IfcStore.redo(until_key=bpy.context.scene.BIMProperties.last_transaction)
purge_module_data()
refresh_ui_data()
tool.Ifc.rebuild_element_maps()
@@ -259,74 +254,58 @@ def viewport_shading_changed_callback(area):
bpy.context.scene.BIMStylesProperties.active_style_type = "External"
if getattr(bpy.types, "SCENE_PT_scene"):
@classmethod
def poll_check_blender_tab(cls, context):
return tool.Blender.is_tab(context, "BLENDER")
class Override_SCENE_PT_scene(bpy.types.SCENE_PT_scene):
bl_idname = "SCENE_PT_scene_override"
def get_override_scene_panel(panel_name):
original_panel = getattr(bpy.types, panel_name)
override_panel = type(f"Override_{panel_name}", (original_panel,), {})
override_panel.bl_idname = f"{panel_name}_override"
# some blender panel depend on other and register_class will throw an error
# if we won't override their `bl_parent_id`
bl_parent_id = getattr(override_panel, "bl_parent_id", None)
if bl_parent_id is not None:
override_panel.bl_parent_id = f"{bl_parent_id}_override"
# override poll method
poll = getattr(override_panel, "poll", None)
if poll is None:
override_panel.poll = poll_check_blender_tab
else:
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "BLENDER")
def wrapped_poll(cls, context):
return super(override_panel, cls).poll(context) and poll_check_blender_tab.__func__(cls, context)
override_panel.poll = wrapped_poll
return override_panel
if getattr(bpy.types, "SCENE_PT_unit"):
class Override_SCENE_PT_unit(bpy.types.SCENE_PT_unit):
bl_idname = "SCENE_PT_unit_override"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "BLENDER")
if getattr(bpy.types, "SCENE_PT_physics"):
class Override_SCENE_PT_physics(bpy.types.SCENE_PT_physics):
bl_idname = "SCENE_PT_physics_override"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "BLENDER")
if getattr(bpy.types, "SCENE_PT_rigid_body_world"):
class Override_SCENE_PT_rigid_body_world(bpy.types.SCENE_PT_rigid_body_world):
bl_idname = "SCENE_PT_rigid_body_world_override"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "BLENDER")
if getattr(bpy.types, "SCENE_PT_audio"):
class Override_SCENE_PT_audio(bpy.types.SCENE_PT_audio):
bl_idname = "SCENE_PT_audio_override"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "BLENDER")
if getattr(bpy.types, "SCENE_PT_keying_sets"):
class Override_SCENE_PT_keying_sets(bpy.types.SCENE_PT_keying_sets):
bl_idname = "SCENE_PT_keying_sets_override"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "BLENDER")
if getattr(bpy.types, "SCENE_PT_custom_props"):
class Override_SCENE_PT_custom_props(bpy.types.SCENE_PT_custom_props):
bl_idname = "SCENE_PT_custom_props_override"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "BLENDER")
# TODO: possibly override scene panels from other addons too?
# list can be updated from
# https://projects.blender.org/blender/blender/src/branch/main/scripts/startup/bl_ui/properties_scene.py#L421
OVERRIDE_SCENE_PANELS = (
"SCENE_PT_scene",
"SCENE_PT_unit",
"SCENE_PT_physics",
"SCENE_PT_rigid_body_world",
"SCENE_PT_rigid_body_world_settings",
"SCENE_PT_rigid_body_cache",
"SCENE_PT_rigid_body_field_weights",
"SCENE_PT_audio",
"SCENE_PT_keying_sets",
"SCENE_PT_custom_props",
# after SCENE_PT_keying_sets
"SCENE_PT_keying_set_paths",
"SCENE_PT_keyframing_settings",
)
if bpy.app.version >= (4, 0):
OVERRIDE_SCENE_PANELS += ("SCENE_PT_simulation",)
@persistent
@@ -355,6 +334,9 @@ def load_post(scene):
ifcopenshell.api.owner.settings.get_application = get_application
AuthoringData.type_thumbnails = {}
if not bpy.context.preferences.addons["blenderbim"].preferences.should_setup_toolbar:
tool.Blender.unregister_toolbar()
if bpy.context.preferences.addons["blenderbim"].preferences.should_setup_workspace:
if "BIM" in bpy.data.workspaces:
bpy.context.window.workspace = bpy.data.workspaces["BIM"]
@@ -364,26 +346,12 @@ def load_post(scene):
# To improve usability for new users, we hijack the scene properties
# tab. We override default scene properties panels with our own poll
# to hide them unless the user has chosen to view Blender properties.
for panel in [
"SCENE_PT_scene",
"SCENE_PT_unit",
"SCENE_PT_physics",
"SCENE_PT_rigid_body_world",
"SCENE_PT_audio",
"SCENE_PT_keying_sets",
"SCENE_PT_custom_props",
]:
if getattr(bpy.types, panel, None):
try:
bpy.utils.register_class(globals()[f"Override_{panel}"])
bpy.utils.unregister_class(getattr(bpy.types, panel))
except:
pass
# https://blender.stackexchange.com/questions/140644/how-can-make-the-state-of-a-boolean-property-relative-to-the-3d-view-area
for screen in bpy.data.screens:
if len(screen.BIMAreaProperties) == 20:
continue
screen.BIMAreaProperties.clear()
for i in range(20): # 20 is an arbitrary value of split areas
screen.BIMAreaProperties.add()
for panel in OVERRIDE_SCENE_PANELS:
if panel in blenderbim.bim.overridden_scene_panels:
continue
override_panel = get_override_scene_panel(panel)
original_panel = getattr(bpy.types, panel)
bpy.utils.register_class(override_panel)
bpy.utils.unregister_class(original_panel)
blenderbim.bim.overridden_scene_panels[panel] = (original_panel, override_panel)
tool.Blender.setup_tabs()
+20 -12
View File
@@ -87,8 +87,15 @@ def import_attributes(ifc_class, props, data, callback=None):
# A more elegant attribute importer signature, intended to supersede import_attributes
def import_attributes2(element, props, callback=None):
for attribute in element.wrapped_data.declaration().as_entity().all_attributes():
import_attribute(attribute, props, element.get_info(), callback=callback)
if isinstance(element, str):
attributes = tool.Ifc.schema().declaration_by_name(element).as_entity().all_attributes()
info = {a.name(): None for a in attributes}
info["type"] = element
else:
attributes = element.wrapped_data.declaration().as_entity().all_attributes()
info = element.get_info()
for attribute in attributes:
import_attribute(attribute, props, info, callback=callback)
def import_attribute(attribute, props, data, callback=None):
@@ -238,7 +245,9 @@ def get_obj_ifc_definition_id(context, obj, obj_type):
].ifc_definition_id
elif obj_type == "WorkSchedule":
return context.scene.BIMWorkScheduleProperties.active_work_schedule_id
elif obj_type == "Group":
prop = context.scene.BIMGroupProperties
return prop.groups[prop.active_group_index].ifc_definition_id
# hack to close popup
# https://blender.stackexchange.com/a/202576/130742
@@ -260,12 +269,7 @@ def convert_property_group_from_si(property_group, skip_props=()):
for prop_name in property_group.bl_rna.properties.keys():
if prop_name in skip_props:
continue
prop_bl_rna = property_group.bl_rna.properties[prop_name]
if prop_bl_rna.array_length > 0:
prop_value = prop_bl_rna.default_array
else:
prop_value = prop_bl_rna.default
prop_value = tool.Blender.get_blender_prop_default_value(property_group, prop_name)
if type(prop_value) is float:
prop_value = prop_value * conversion_k
elif type(prop_value) is bpy.types.bpy_prop_array:
@@ -273,7 +277,7 @@ def convert_property_group_from_si(property_group, skip_props=()):
setattr(property_group, prop_name, prop_value)
def draw_filter(layout, props, data, module):
def draw_filter(layout, filter_groups, data, module):
if not data.is_loaded:
data.load()
@@ -291,7 +295,7 @@ def draw_filter(layout, props, data, module):
row.operator("bim.add_filter_group", text="Add Search Group", icon="ADD").module = module
row.operator("bim.edit_filter_query", text="", icon="FILTER").module = module
for i, filter_group in enumerate(props.filter_groups):
for i, filter_group in enumerate(filter_groups):
box = layout.box()
row = box.row(align=True)
@@ -319,13 +323,17 @@ def draw_filter(layout, props, data, module):
row = box.row(align=True)
row.prop(ifc_filter, "pset", text="", icon="PROPERTIES")
row.prop(ifc_filter, "name", text="")
row.prop(ifc_filter, "comparison", text="")
row.prop(ifc_filter, "value", text="")
elif ifc_filter.type == "classification":
row = box.row(align=True)
row.prop(ifc_filter, "value", text="", icon="OUTLINER")
elif ifc_filter.type == "location":
row = box.row(align=True)
row.prop(ifc_filter, "name", text="", icon="PACKAGE")
row.prop(ifc_filter, "value", text="", icon="PACKAGE")
elif ifc_filter.type == "group":
row = box.row(align=True)
row.prop(ifc_filter, "value", text="", icon="OUTLINER_COLLECTION")
elif ifc_filter.type == "query":
row = box.row(align=True)
row.prop(ifc_filter, "name", text="", icon="POINTCLOUD_DATA")
+7 -2
View File
@@ -80,8 +80,8 @@ class IfcStore:
if IfcStore.path:
try:
IfcStore.load_file(IfcStore.path)
except:
pass
except Exception as e:
print(f"Failed to load file {IfcStore.path}. Error details: {e}")
return IfcStore.file
@staticmethod
@@ -163,8 +163,12 @@ class IfcStore:
if not IfcStore.get_file():
return
for obj in bpy.data.objects:
if obj.library:
continue
IfcStore.relink_object(obj)
for obj in bpy.data.materials:
if obj.library:
continue
IfcStore.relink_object(obj)
@staticmethod
@@ -317,6 +321,7 @@ class IfcStore:
@staticmethod
def execute_ifc_operator(operator, context, is_invoke=False):
bpy.context.scene.BIMProperties.is_dirty = True
is_top_level_operator = not bool(IfcStore.current_transaction)
if is_top_level_operator:
File diff suppressed because it is too large Load Diff
@@ -20,14 +20,14 @@ import bpy
from . import ui, prop, operator
classes = (
operator.BIM_OT_assign_object,
operator.BIM_OT_unassign_object,
operator.BIM_OT_enable_editing_aggregate,
operator.BIM_OT_disable_editing_aggregate,
operator.BIM_OT_add_aggregate,
operator.BIM_OT_select_parts,
operator.BIM_OT_select_aggregate,
operator.BIM_OT_add_part_to_object,
operator.BIM_OT_aggregate_assign_object,
operator.BIM_OT_disable_editing_aggregate,
operator.BIM_OT_enable_editing_aggregate,
operator.BIM_OT_select_aggregate,
operator.BIM_OT_select_parts,
operator.BIM_OT_aggregate_unassign_object,
prop.BIMObjectAggregateProperties,
ui.BIM_PT_aggregate,
)
@@ -35,7 +35,7 @@ class AggregateData:
"has_relating_object": cls.has_relating_object(),
"relating_object_label": cls.get_relating_object_label(),
"has_related_objects": cls.has_related_objects(),
"related_objects_amount": cls.get_related_objects_amount(),
"total_parts": cls.total_parts(),
"ifc_class": cls.ifc_class(),
}
cls.is_loaded = True
@@ -59,7 +59,7 @@ class AggregateData:
return ifcopenshell.util.element.get_parts(tool.Ifc.get_entity(bpy.context.active_object))
@classmethod
def get_related_objects_amount(cls):
def total_parts(cls):
parts = cls.get_related_objects()
return len(parts) if parts else 0
@@ -33,11 +33,11 @@ class Operator:
return {"FINISHED"}
class BIM_OT_assign_object(bpy.types.Operator, Operator):
class BIM_OT_aggregate_assign_object(bpy.types.Operator, Operator):
"""Create aggregation relationship between two ifc elements"""
bl_idname = "bim.assign_object"
bl_label = "Assign Object"
bl_idname = "bim.aggregate_assign_object"
bl_label = "Assign Object To Aggregation"
bl_options = {"REGISTER", "UNDO"}
relating_object: bpy.props.IntProperty()
@@ -67,11 +67,11 @@ class BIM_OT_assign_object(bpy.types.Operator, Operator):
self.report({"ERROR"}, f" Cannot aggregate {obj.name} to {relating_obj.name}")
class BIM_OT_unassign_object(bpy.types.Operator, Operator):
class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator):
"""Remove aggregation relationship between two ifc elements"""
bl_idname = "bim.unassign_object"
bl_label = "Unassign Object"
bl_idname = "bim.aggregate_unassign_object"
bl_label = "Unassign Object From Aggregation"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
@@ -164,6 +164,7 @@ class BIM_OT_add_aggregate(bpy.types.Operator, tool.Ifc.Operator):
def create_aggregate(self, context, ifc_class):
aggregate = bpy.data.objects.new("Assembly", None)
aggregate.location = context.scene.cursor.location
bpy.ops.bim.assign_class(obj=aggregate.name, ifc_class=ifc_class)
return aggregate
@@ -202,6 +203,7 @@ class BIM_OT_select_aggregate(bpy.types.Operator):
aggregate_obj = tool.Ifc.get_object(aggregate)
if aggregate_obj in context.selectable_objects:
aggregate_obj.select_set(True)
bpy.context.view_layer.objects.active = aggregate_obj
return {"FINISHED"}
@@ -54,7 +54,7 @@ class BIM_PT_aggregate(Panel):
row = layout.row(align=True)
row.prop(props, "relating_object", text="")
if props.relating_object:
op = row.operator("bim.assign_object", icon="CHECKMARK", text="")
op = row.operator("bim.aggregate_assign_object", icon="CHECKMARK", text="")
op.relating_object = props.relating_object.BIMObjectProperties.ifc_definition_id
row.operator("bim.disable_editing_aggregate", icon="CANCEL", text="")
else:
@@ -65,15 +65,21 @@ class BIM_PT_aggregate(Panel):
op.obj = context.active_object.name
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
row.operator("bim.add_aggregate", icon="ADD", text="")
op = row.operator("bim.unassign_object", icon="X", text="")
op = row.operator("bim.aggregate_unassign_object", icon="X", text="")
else:
row.label(text="No Aggregate", icon="TRIA_UP")
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
row.operator("bim.add_aggregate", icon="ADD", text="")
row = layout.row(align=True)
parts = AggregateData.data["related_objects_amount"]
row.label(text=f"{parts or 'No'} Part{'s' if parts > 1 else ''}", icon="TRIA_DOWN")
total_parts = AggregateData.data["total_parts"]
if total_parts == 0:
row.label(text="No Parts", icon="TRIA_DOWN")
elif total_parts == 1:
row.label(text="1 Part", icon="TRIA_DOWN")
else:
row.label(text=f"{total_parts} Parts", icon="TRIA_DOWN")
if AggregateData.data["has_related_objects"]:
op = row.operator("bim.select_parts", icon="RESTRICT_SELECT_OFF", text="")
op.obj = context.active_object.name
@@ -16,6 +16,8 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import os
import bpy
import bcf
import bcf.v2.bcfxml
@@ -23,12 +25,31 @@ import bcf.v2.bcfxml
class BcfStore:
bcfxml = None
@staticmethod
def get_bcfxml():
if not BcfStore.bcfxml:
BcfStore.bcfxml = bcf.v2.bcfxml.BcfXml()
return BcfStore.bcfxml
@classmethod
def get_bcfxml(cls):
if not cls.bcfxml:
bcf_filepath = bpy.context.scene.BCFProperties.bcf_file
if not os.path.isabs(bcf_filepath):
bcf_filepath = os.path.abspath(os.path.join(bpy.path.abspath("//"), bcf_filepath))
if bcf_filepath:
try:
cls.bcfxml = bcf.bcfxml.load(bcf_filepath)
except:
# there will be a plenty of "Permission denied" errors
# as many poll() methods will try to access the bcfxml simultaneously
# the first time it's loaded
pass
return cls.bcfxml
@classmethod
def set(cls, bcfxml):
def set(cls, bcfxml, filepath):
cls.bcfxml = bcfxml
bpy.context.scene.BCFProperties.bcf_file = filepath
@classmethod
def set_by_filepath(cls, filepath):
cls.set(None, filepath)
@classmethod
def unload_bcfxml(cls):
cls.set(None, "")
@@ -42,11 +42,9 @@ class NewBcfProject(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BCFProperties.is_loaded = False
bcfxml = bcf.v2.bcfxml.BcfXml.create_new("New Project")
bcfstore.BcfStore.set(bcfxml)
bcfstore.BcfStore.set(bcfxml, "")
bpy.ops.bim.load_bcf_project()
context.scene.BCFProperties.is_loaded = True
return {"FINISHED"}
@@ -59,11 +57,10 @@ class LoadBcfProject(bpy.types.Operator):
def execute(self, context):
if self.filepath:
bcfstore.BcfStore.bcfxml = bcf.bcfxml.load(self.filepath)
bcfstore.BcfStore.set_by_filepath(self.filepath)
bcfxml = bcfstore.BcfStore.get_bcfxml()
context.scene.BCFProperties.name = bcfxml.project.name
bpy.ops.bim.load_bcf_topics()
context.scene.BCFProperties.is_loaded = True
return {"FINISHED"}
def invoke(self, context, event):
@@ -77,8 +74,7 @@ class UnloadBcfProject(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
bcfstore.BcfStore.set(None)
context.scene.BCFProperties.is_loaded = False
bcfstore.BcfStore.unload_bcfxml()
return {"FINISHED"}
@@ -267,6 +263,7 @@ class SaveBcfProject(bpy.types.Operator):
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
bcfxml.save(self.filepath)
bcfstore.BcfStore.set(bcfxml, self.filepath)
return {"FINISHED"}
def invoke(self, context, event):
@@ -964,7 +961,8 @@ class ActivateBcfViewpoint(bpy.types.Operator):
context_override = {}
context_override["object"] = context_override["active_object"] = objs[0]
context_override["selected_objects"] = context_override["selected_editable_objects"] = objs
bpy.ops.object.hide_view_set(context_override, unselected=True)
with context.temp_override(**context_override):
bpy.ops.object.hide_view_set(unselected=True)
context.area.type = old
if viewpoint.visualization_info.components.view_setup_hints:
@@ -978,14 +976,16 @@ class ActivateBcfViewpoint(bpy.types.Operator):
self.hide_spaces(context)
self.set_openings_visibility(False, context)
# set selection at the end not to conflict with .hide_spaces
self.set_selection(viewpoint)
self.set_colours(viewpoint)
def hide_spaces(self, context):
old = context.area.type
context.area.type = "VIEW_3D"
bpy.ops.object.select_all(action="DESELECT")
bpy.ops.object.select_pattern(pattern="IfcSpace/*")
bpy.ops.object.hide_view_set({})
bpy.ops.object.hide_view_set()
context.area.type = old
def set_openings_visibility(self, is_visible, context):
@@ -41,37 +41,37 @@ def purge():
def updateBcfReferenceLink(self, context):
if context.scene.BCFProperties.is_loaded:
if bcfstore.BcfStore.get_bcfxml():
bpy.ops.bim.edit_bcf_reference_links()
def updateBcfLabel(self, context):
if context.scene.BCFProperties.is_loaded:
if bcfstore.BcfStore.get_bcfxml():
bpy.ops.bim.edit_bcf_labels()
def updateBcfProjectName(self, context):
if self.is_loaded:
if bcfstore.BcfStore.get_bcfxml():
bpy.ops.bim.edit_bcf_project_name()
def updateBcfAuthor(self, context):
if self.is_loaded:
if bcfstore.BcfStore.get_bcfxml():
bpy.ops.bim.edit_bcf_author()
def updateBcfTopicName(self, context):
if context.scene.BCFProperties.is_loaded:
if bcfstore.BcfStore.get_bcfxml():
bpy.ops.bim.edit_bcf_topic_name()
def updateBcfTopicIsEditable(self, context):
if context.scene.BCFProperties.is_loaded and not self.is_editable:
if bcfstore.BcfStore.get_bcfxml() and not self.is_editable:
bpy.ops.bim.edit_bcf_topic()
def updateBcfCommentIsEditable(self, context):
if context.scene.BCFProperties.is_loaded and not self.is_editable:
if bcfstore.BcfStore.get_bcfxml() and not self.is_editable:
bpy.ops.bim.edit_bcf_comment(comment_guid=self.name)
@@ -151,7 +151,7 @@ class BcfTopic(PropertyGroup):
class BCFProperties(PropertyGroup):
is_loaded: BoolProperty(name="Is Loaded", default=False)
bcf_file: StringProperty(name="BCF File")
comment_text_width: IntProperty(name="Comment Text Width", default=40)
name: StringProperty(default="", name="Project Name", update=updateBcfProjectName)
author: StringProperty(default="john@doe.com", name="Author Email", update=updateBcfAuthor)
@@ -39,8 +39,7 @@ class BIM_PT_bcf(Panel):
scene = context.scene
props = scene.BCFProperties
if not props.is_loaded:
if not bcfstore.BcfStore.get_bcfxml():
row = layout.row(align=True)
row.operator("bim.new_bcf_project", text="New Project")
row.operator("bim.load_bcf_project", text="Load Project")
@@ -62,14 +62,14 @@ class BoundaryDecorator:
gpu.state.point_size_set(6)
gpu.state.blend_set("ALPHA")
self.line_shader = gpu.shader.from_builtin("3D_POLYLINE_UNIFORM_COLOR")
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
self.line_shader.bind() # required to be able to change uniforms of the shader
# POLYLINE_UNIFORM_COLOR specific uniforms
self.line_shader.uniform_float("viewportSize", (context.region.width, context.region.height))
self.line_shader.uniform_float("lineWidth", 2.0)
# general shader
self.shader = gpu.shader.from_builtin("3D_UNIFORM_COLOR")
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
selected_vertices = []
selected_edges = []
@@ -22,6 +22,7 @@ import logging
import shapely
import mathutils
import numpy as np
import multiprocessing
import ifcopenshell.api
import ifcopenshell.util.unit
import ifcopenshell.util.shape
@@ -30,7 +31,7 @@ import ifcopenshell.util.placement
import ifcopenshell.util.representation
import blenderbim.tool as tool
import blenderbim.bim.import_ifc as import_ifc
from math import pi, inf
from math import pi, inf, degrees, acos, radians
from mathutils import Vector, Matrix
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.decorator import ProfileDecorator
@@ -63,7 +64,8 @@ def disable_editing_boundary_geometry(context):
class Loader:
def __init__(self):
def __init__(self, operator=None):
self.operator = operator
self.ifc_file = None
self.logger = None
self.ifc_importer = None
@@ -85,14 +87,33 @@ class Loader:
tool.Loader.link_mesh(shape, mesh)
except RuntimeError:
# Fallback solution for invalid geometry provided by Revit. (InnerBoundaries cuting OuterBoundary)
print(f"Failed to create mesh from IfcRelSpaceBoundary with ID {boundary.id()}. Geometry might be invalid")
shape = ifcopenshell.geom.create_shape(self.fallback_settings, surface.OuterBoundary)
self.operator.report(
{"WARNING"},
(
f"IfcRelSpaceBoundary {boundary.id()} mesh creation failed. Geometry might be invalid. Using fallback solution"
),
)
try:
shape = ifcopenshell.geom.create_shape(self.fallback_settings, surface.OuterBoundary)
except RuntimeError:
self.operator.report(
{"WARNING"},
f"Skipping IfcRelSpaceBoundary {boundary.id()}. Fallback solution failed. Geometry might be invalid",
)
return None
mesh = bpy.data.meshes.new(str(surface.id()))
bm = bmesh.new()
verts = [bm.verts.new(shape.verts[i : i + 3]) for i in range(0, len(shape.verts), 3)]
bm.faces.new(verts)
for inner_boundary in surface.InnerBoundaries:
shape = ifcopenshell.geom.create_shape(self.fallback_settings, inner_boundary)
try:
shape = ifcopenshell.geom.create_shape(self.fallback_settings, inner_boundary)
except RuntimeError:
self.operator.report(
{"WARNING"},
f"Skipping an inner boundary for IfcRelSpaceBoundary with ID {boundary.id()}. Geometry might be invalid",
)
return None
verts = [bm.verts.new(shape.verts[i : i + 3]) for i in range(0, len(shape.verts), 3)]
for i in range(len(verts) - 1):
bm.edges.new(verts[i : i + 2])
@@ -103,7 +124,7 @@ class Loader:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
matrix = mathutils.Matrix(
ifcopenshell.util.placement.get_axis2placement(surface.BasisSurface.Position).tolist()
)
)
matrix.translation *= unit_scale
mesh.transform(matrix)
return mesh
@@ -126,7 +147,15 @@ class Loader:
self.ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
self.ifc_importer.file = self.ifc_file
def load_boundary(self, boundary, blender_space):
def load_boundary(self, boundary, blender_space=None):
if not blender_space:
if not boundary.RelatingSpace:
self.operator.report(
{"WARNING"},
f"Skipping IfcRelSpaceBoundary {boundary.id()} which have no relating space. Invalid boundary.",
)
return
blender_space = tool.Ifc.get_object(boundary.RelatingSpace)
obj = tool.Ifc.get_object(boundary)
if obj:
return obj
@@ -145,9 +174,9 @@ class LoadProjectSpaceBoundaries(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
loader = Loader()
loader = Loader(self)
for rel in tool.Ifc.get().by_type("IfcRelSpaceBoundary"):
loader.load_boundary(rel, tool.Ifc.get_object(rel.RelatingSpace))
loader.load_boundary(rel)
return {"FINISHED"}
@@ -158,7 +187,7 @@ class LoadBoundary(bpy.types.Operator):
boundary_id: bpy.props.IntProperty()
def execute(self, context):
loader = Loader()
loader = Loader(self)
for obj in context.visible_objects:
obj.select_set(False)
obj = loader.load_boundary(tool.Ifc.get().by_id(self.boundary_id), context.active_object)
@@ -173,7 +202,7 @@ class LoadSpaceBoundaries(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
loader = Loader()
loader = Loader(self)
element = tool.Ifc.get_entity(context.active_object)
for rel in element.BoundedBy or []:
loader.load_boundary(rel, context.active_object)
@@ -421,7 +450,7 @@ class EnableEditingBoundaryGeometry(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.object.mode_set(mode="EDIT")
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: disable_editing_boundary_geometry(context))
if not bpy.app.background:
bpy.ops.wm.tool_set_by_id(tool.Blender.get_viewport_context(), name="bim.cad_tool")
tool.Blender.set_viewport_tool("bim.cad_tool")
return {"FINISHED"}
@@ -459,7 +488,7 @@ class EditBoundaryGeometry(bpy.types.Operator, tool.Ifc.Operator):
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_surface)
old_mesh = obj.data
loader = Loader()
loader = Loader(self)
obj.data = loader.create_mesh(element)
tool.Geometry.delete_data(old_mesh)
@@ -484,7 +513,7 @@ class ShowBoundaries(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
props = bpy.context.scene.BIMBoundaryProperties
loader = Loader()
loader = Loader(self)
for obj in context.selected_objects:
element = tool.Ifc.get_entity(obj)
if not element or not getattr(element, "BoundedBy", None):
@@ -538,6 +567,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
related_building_element = None
relating_space_obj = None
related_building_element_obj = None
parent_boundaries = []
objs = context.selected_objects
if len(objs) == 2:
@@ -552,8 +582,19 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
else:
related_building_element = element
related_building_element_obj = obj
parent_boundary = self.create_element_boundary(
context, relating_space, relating_space_obj, related_building_element, related_building_element_obj
)
if parent_boundary:
parent_boundaries.append(parent_boundary)
elif len(objs) == 1:
# New prototype, old code not yet removed. Still testing.
space = tool.Ifc.get_entity(objs[0])
if space.is_a("IfcSpace"):
self.auto_generate_boundaries(space, objs[0])
elif len(objs) == 1:
# Optionally the user may select just the space, and the building element shall be auto-detected
# TODO : refactor to be able to generate all boundaries for selected space automatically or with an option
def msg(self, context):
self.layout.label(text="NO ACTIVE STOREY")
@@ -563,8 +604,6 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
relating_space = element
relating_space_obj = objs[0]
target = bpy.context.scene.cursor.location
collection = context.view_layer.active_layer_collection.collection
collection_obj = bpy.data.objects.get(collection.name)
if not collection_obj:
@@ -576,19 +615,258 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
return
for subelement in ifcopenshell.util.element.get_decomposition(spatial_element):
if not (subelement.is_a("IfcWall") or subelement.is_a("IfcSlab")):
if not (
subelement.is_a("IfcWall") or subelement.is_a("IfcSlab") or subelement.is_a("IfcVirtualElement")
):
continue
obj = tool.Ifc.get_object(subelement)
if obj:
raycast = obj.closest_point_on_mesh(obj.matrix_world.inverted() @ target, distance=0.1)
if raycast[0]:
related_building_element = subelement
related_building_element_obj = obj
break
related_building_element = subelement
related_building_element_obj = obj
parent_boundary = self.create_element_boundary(
context,
relating_space,
relating_space_obj,
related_building_element,
related_building_element_obj,
)
if parent_boundary:
parent_boundaries.append(parent_boundary)
bpy.ops.bim.show_boundaries()
for parent_boundary in parent_boundaries:
obj = tool.Ifc.get_object(parent_boundary)
obj.select_set(True)
def auto_generate_boundaries(self, space, space_obj):
# Identify all potential building elements
# TODO: don't select everything, use AABB culling in Blender
building_elements = (
tool.Ifc.get().by_type("IfcWall")
+ tool.Ifc.get().by_type("IfcSlab")
+ tool.Ifc.get().by_type("IfcVirtualElement")
)
# Don't generate boundaries of building elements that we've already got bounaries for.
for boundary in space.BoundedBy:
if boundary.RelatedBuildingElement in building_elements:
building_elements.remove(boundary.RelatedBuildingElement)
# Create tree of gross shapes of all potential related building elements
include = building_elements + [space]
tree = ifcopenshell.geom.tree()
shapes = {}
settings = ifcopenshell.geom.settings()
settings.set(settings.STRICT_TOLERANCE, True)
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, True)
iterator = ifcopenshell.geom.iterator(settings, tool.Ifc.get(), multiprocessing.cpu_count(), include=include)
if iterator.initialize():
while True:
tree.add_element(iterator.get_native())
shape = iterator.get()
shapes[shape.id] = shape
if not iterator.next():
break
# Spatially query all potential boundary elements via a 100mm extension of the space
building_elements = [e for e in tree.select(space, extend=0.1) if e != space]
if not building_elements:
return
# Create a dissolved bmesh for the space
space_bm = bmesh.new()
space_bm.from_mesh(space_obj.data)
bmesh.ops.dissolve_limit(space_bm, angle_limit=pi * 2 / 360, verts=space_bm.verts, edges=space_bm.edges)
# Create dissolved bmeshes for all boundary elements
building_element_bms = {}
for building_element in building_elements:
bm = bmesh.new()
shape = shapes[building_element.id()]
verts = ifcopenshell.util.shape.get_vertices(shape.geometry)
for vert in verts:
bm.verts.new(Vector(vert))
bm.verts.ensure_lookup_table()
faces = ifcopenshell.util.shape.get_faces(shape.geometry)
for face in faces:
bm.faces.new([bm.verts[i] for i in face])
bm.verts.ensure_lookup_table()
bm.faces.ensure_lookup_table()
bm.normal_update() # Needed so that dissolve_limit will work.
bmesh.ops.dissolve_limit(bm, angle_limit=radians(1), verts=bm.verts[:], edges=bm.edges[:])
bm.verts.ensure_lookup_table()
bm.faces.ensure_lookup_table()
building_element_bms[building_element.id()] = bm
# Compare space faces and building element faces to see if they relate to one another
for space_face in space_bm.faces:
space_face_normal = space_obj.matrix_world.to_3x3() @ space_face.normal
space_face_vert = space_obj.matrix_world @ space_face.verts[0].co
for building_element in building_elements:
for face in building_element_bms[building_element.id()].faces:
building_obj = tool.Ifc.get_object(building_element)
face_normal = building_obj.matrix_world.to_3x3() @ face.normal
angle = degrees(acos(max(min(space_face_normal.dot(face_normal), 1), -1)))
if tool.Cad.is_x(angle, 180, tolerance=2):
pass # Faces need to be parallel and have opposite normals to be related.
elif building_element.is_a("IfcVirtualElement") and tool.Cad.is_x(angle, 0, tolerance=2):
pass # Virtual elements only need to be parallel to be related, since they are planes.
else:
continue
# Both faces should be close to one another. Say within 50mm.
space_vert = building_obj.matrix_world.inverted() @ space_face_vert
dist = mathutils.geometry.distance_point_to_plane(space_vert, face.verts[0].co, face.normal)
if abs(dist) > 0.05:
continue
# Project the building element face onto the space face
space_face_verts = [v.co.copy() for v in space_face.verts]
space_face_matrix = self.get_face_matrix(*[v.copy() for v in space_face_verts[0:3]])
space_face_matrix_i = space_face_matrix.inverted()
space_face_polygon = shapely.Polygon(
[tuple((space_face_matrix_i @ v).xy) for v in space_face_verts]
)
space_matrix_world_i = space_obj.matrix_world.inverted()
face_verts = [space_matrix_world_i @ building_obj.matrix_world @ v.co.copy() for v in face.verts]
face_polygon = shapely.Polygon([tuple((space_face_matrix_i @ v).xy) for v in face_verts])
gross_boundary_polygon = space_face_polygon.intersection(face_polygon)
if type(gross_boundary_polygon) == shapely.GeometryCollection:
for geom in gross_boundary_polygon.geoms:
if type(geom) == shapely.Polygon:
gross_boundary_polygon = geom
break
if (
not (isinstance(gross_boundary_polygon, shapely.Polygon) and gross_boundary_polygon.is_valid)
or gross_boundary_polygon.is_empty
):
continue
# The gross boundary polygon may not be a true gross boundary since it
# may have openings already removed, such as in IFC4 Reference View. So
# we cheat by using the exterior boundary to mean "gross".
exterior_boundary_polygon = shapely.Polygon(gross_boundary_polygon.exterior.coords)
parent_boundary = tool.Ifc.run(
"root.create_entity", ifc_class=bpy.context.scene.BIMModelProperties.boundary_class
)
if building_element.is_a("IfcVirtualElement"):
parent_boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
else:
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
parent_boundary.InternalOrExternalBoundary = "NOTDEFINED"
if building_element.is_a("IfcWall"):
is_external = ifcopenshell.util.element.get_pset(
building_element, "Pset_WallCommon", "IsExternal"
)
if is_external is True:
parent_boundary.InternalOrExternalBoundary = "EXTERNAL"
elif is_external is False:
parent_boundary.InternalOrExternalBoundary = "INTERNAL"
elif building_element.is_a("IfcSlab"):
predefined_type = ifcopenshell.util.element.get_predefined_type(building_element)
if predefined_type == "BASESLAB":
parent_boundary.InternalOrExternalBoundary = "EXTERNAL_EARTH"
else:
is_external = ifcopenshell.util.element.get_pset(
building_element, "Pset_SlabCommon", "IsExternal"
)
if is_external is True:
parent_boundary.InternalOrExternalBoundary = "EXTERNAL"
elif is_external is False:
parent_boundary.InternalOrExternalBoundary = "INTERNAL"
parent_boundary.RelatingSpace = space
parent_boundary.RelatedBuildingElement = building_element
parent_boundary.ConnectionGeometry = self.create_connection_geometry_from_polygon(
exterior_boundary_polygon, space_face_matrix
)
self.set_boundary_name(parent_boundary)
for rel in getattr(building_element, "HasOpenings", []):
opening = rel.RelatedOpeningElement
filling = opening.HasFillings[0].RelatedBuildingElement if opening.HasFillings else None
# Create shape of opening as a dissolved BMesh
settings = ifcopenshell.geom.settings()
settings.set(settings.STRICT_TOLERANCE, True)
shape = ifcopenshell.geom.create_shape(settings, opening)
m = shape.transformation.matrix.data
mat = Matrix(
(
[m[0], m[3], m[6], m[9]],
[m[1], m[4], m[7], m[10]],
[m[2], m[5], m[8], m[11]],
[0, 0, 0, 1],
)
)
opening_bm = bmesh.new()
verts = ifcopenshell.util.shape.get_vertices(shape.geometry)
for vert in verts:
opening_bm.verts.new(Vector(vert))
opening_bm.verts.ensure_lookup_table()
faces = ifcopenshell.util.shape.get_faces(shape.geometry)
for face in faces:
opening_bm.faces.new([opening_bm.verts[i] for i in face])
opening_bm.verts.ensure_lookup_table()
opening_bm.faces.ensure_lookup_table()
opening_bm.normal_update() # Needed so that dissolve_limit will work.
bmesh.ops.dissolve_limit(
opening_bm, angle_limit=radians(1), verts=opening_bm.verts[:], edges=opening_bm.edges[:]
)
opening_bm.verts.ensure_lookup_table()
opening_bm.faces.ensure_lookup_table()
# Get relevant faces of BMesh that can turn into boundaries
opening_polygons = []
for opening_face in opening_bm.faces:
opening_face_normal = mat.to_3x3() @ opening_face.normal
angle = degrees(acos(max(min(opening_face_normal.dot(face_normal), 1), -1)))
if not tool.Cad.is_x(angle, 180, tolerance=2):
continue # Any non-parallel faces are not relevant
opening_face_verts = [space_matrix_world_i @ mat @ v.co.copy() for v in opening_face.verts]
polygon = shapely.Polygon([tuple((space_face_matrix_i @ v).xy) for v in opening_face_verts])
opening_polygons.append(polygon)
# Merge them all into a single opening polygon for our boundary
opening_polygon = shapely.ops.unary_union(opening_polygons)
# Only openings that are projected onto our exterior boundary are relevant.
if opening_polygon.intersection(exterior_boundary_polygon).area == 0:
continue
boundary = tool.Ifc.run(
"root.create_entity", ifc_class=bpy.context.scene.BIMModelProperties.boundary_class
)
boundary.RelatingSpace = space
boundary.RelatedBuildingElement = filling or opening
boundary.ConnectionGeometry = self.create_connection_geometry_from_polygon(
opening_polygon, space_face_matrix
)
if filling:
boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
else:
boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
boundary.InternalOrExternalBoundary = parent_boundary.InternalOrExternalBoundary
if boundary.is_a() != "IfcRelSpaceBoundary":
boundary.ParentBoundary = parent_boundary
self.set_boundary_name(boundary)
def create_element_boundary(
self, context, relating_space, relating_space_obj, related_building_element, related_building_element_obj
):
if not relating_space or not related_building_element:
return
# Find which face on space should be bounded to related building element
# TODO: Handle round wall where multiple faces need to be bound to the same related building element
bm = bmesh.new()
bm.from_mesh(relating_space_obj.data)
bmesh.ops.dissolve_limit(bm, angle_limit=pi * 2 / 360, verts=bm.verts, edges=bm.edges)
@@ -609,8 +887,6 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
if not target_face:
return
parent_boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class)
# Is this right? Or should I use loop?
target_face_verts = [v.co.copy() for v in target_face.verts]
target_face_matrix = self.get_face_matrix(*[v.copy() for v in target_face_verts[0:3]])
@@ -630,6 +906,18 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
gross_boundary_polygon = geom
break
if (
not (isinstance(gross_boundary_polygon, shapely.Polygon) and gross_boundary_polygon.is_valid)
or gross_boundary_polygon.is_empty
):
return
parent_boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class)
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
# Set to EXTERNAL by default and turn later to internal if there is a corresponding boundary relating to an
# internal space
parent_boundary.InternalOrExternalBoundary = "EXTERNAL"
# The gross boundary polygon may not be a true gross boundary since it
# may have openings already removed, such as in IFC4 Reference View. So
# we cheat by using the exterior boundary to mean "gross". Later, we
@@ -637,19 +925,25 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
# space.
exterior_boundary_polygon = shapely.Polygon(gross_boundary_polygon.exterior.coords)
net_boundary_polygon = shapely.Polygon(gross_boundary_polygon)
inner_boundaries = []
for rel in getattr(related_building_element, "HasOpenings", []):
opening = rel.RelatedOpeningElement
filling = None
if opening.HasFillings:
filling = opening.HasFillings[0].RelatedBuildingElement
if not opening.HasFillings:
continue
# TODO: HasFilling is a zero to many relationship. How to handle many ?
filling = opening.HasFillings[0].RelatedBuildingElement
opening_polygon = self.get_flattened_polygon(opening, relating_space_obj, target_face_matrix_i)
net_boundary_polygon = net_boundary_polygon.difference(opening_polygon)
# An inner boundary is supposed to overlap its parent boundary according to IFC4 documentation
# so we extend our exterior boundary with all opening which has a filling
# Also see Implementation aggreement SB 1.1 for IFC 2x3 TC1 Space Boundary Addon View
# https://standards.buildingsmart.org/MVD/RELEASE/IFC2x3/TC1/SB1_1/IFC%20Space%20Boundary%20Implementation%20Agreement%20Addendum%202010-03-22.pdf
unionised_object = exterior_boundary_polygon.union(opening_polygon)
if isinstance(unionised_object, shapely.Polygon):
exterior_boundary_polygon = unionised_object
# Only openings that are projected onto our exterior boundary are relevant.
if opening_polygon.intersection(exterior_boundary_polygon).area == 0:
continue
@@ -657,24 +951,25 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
connection_geometry = self.create_connection_geometry_from_polygon(opening_polygon, target_face_matrix)
boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class)
boundary.RelatingSpace = relating_space
boundary.RelatedBuildingElement = filling or related_building_element
boundary.RelatedBuildingElement = filling
boundary.ConnectionGeometry = connection_geometry
boundary.PhysicalOrVirtualBoundary = "PHYSICAL" if filling else "VIRTUAL"
boundary.InternalOrExternalBoundary = "INTERNAL"
if related_building_element.is_a("IfcVirtualElement"):
boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
else:
boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
boundary.InternalOrExternalBoundary = parent_boundary.InternalOrExternalBoundary
self.set_boundary_name(boundary)
if boundary.is_a("IfcRelSpaceBoundary2ndLevel"):
boundary.ParentBoundary = parent_boundary
connection_geometry = self.create_connection_geometry_from_polygon(net_boundary_polygon, target_face_matrix)
connection_geometry = self.create_connection_geometry_from_polygon(
exterior_boundary_polygon, target_face_matrix
)
parent_boundary.RelatingSpace = relating_space
parent_boundary.RelatedBuildingElement = related_building_element
parent_boundary.ConnectionGeometry = connection_geometry
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
parent_boundary.InternalOrExternalBoundary = "INTERNAL"
bpy.ops.bim.show_boundaries()
obj = tool.Ifc.get_object(parent_boundary)
obj.select_set(True)
self.set_boundary_name(parent_boundary)
return parent_boundary
def get_face_matrix(self, p1, p2, p3):
edge1 = p2 - p1
@@ -729,11 +1024,13 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
tool.Model.unit_scale = self.unit_scale
surface = tool.Ifc.get().createIfcCurveBoundedPlane()
surface.BasisSurface = tool.Ifc.get().createIfcPlane(tool.Ifc.get().createIfcAxis2Placement3D(
tool.Ifc.get().createIfcCartesianPoint([o / self.unit_scale for o in p1]),
tool.Ifc.get().createIfcDirection([float(o) for o in z_axis]),
tool.Ifc.get().createIfcDirection([float(o) for o in x_axis]),
))
surface.BasisSurface = tool.Ifc.get().createIfcPlane(
tool.Ifc.get().createIfcAxis2Placement3D(
tool.Ifc.get().createIfcCartesianPoint([o / self.unit_scale for o in p1]),
tool.Ifc.get().createIfcDirection([float(o) for o in z_axis]),
tool.Ifc.get().createIfcDirection([float(o) for o in x_axis]),
)
)
if tool.Ifc.get().schema != "IFC2X3":
points = [tool.Model.convert_si_to_unit(list(co)) for co in polygon.exterior.coords]
@@ -746,9 +1043,24 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
point_list = tool.Ifc.get().createIfcCartesianPointList2D(points)
inner_boundaries.append(tool.Ifc.get().createIfcIndexedPolyCurve(point_list, None, False))
else:
pass # TODO
pass # TODO
surface.OuterBoundary = outer_boundary
surface.InnerBoundaries = inner_boundaries
return surface
def set_boundary_name(self, boundary):
"""
By convention 1stLevel and 2ndLevel boundary have specific name and description
See https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRelSpaceBoundary.htm
Warning: IfcRelSpaceBoundary2ndLevel is a subclass of IfcRelSpaceBoundary1stLevel test order matter
"""
if boundary.is_a("IfcRelSpaceBoundary2ndLevel"):
boundary.Name = "2ndLevel"
if boundary.CorrespondingBoundary:
boundary.Description = "2a"
else:
boundary.Description = "2b"
elif boundary.is_a("IfcRelSpaceBoundary1stLevel"):
boundary.Name = "1stLevel"
@@ -31,7 +31,7 @@ class BIM_PT_SceneBoundaries(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_geometry"
bl_parent_id = "BIM_PT_tab_geometry"
@classmethod
def poll(cls, context):
@@ -0,0 +1,42 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
classes = (
operator.GetBSDDClassificationProperties,
operator.LoadBSDDDomains,
operator.SearchBSDDClass,
operator.SetActiveBSDDDictionary,
prop.BSDDDomain,
prop.BSDDClassification,
prop.BSDDPset,
prop.BIMBSDDProperties,
ui.BIM_UL_bsdd_domains,
ui.BIM_UL_bsdd_classifications,
ui.BIM_PT_bsdd,
)
def register():
bpy.types.Scene.BIMBSDDProperties = bpy.props.PointerProperty(type=prop.BIMBSDDProperties)
def unregister():
del bpy.types.Scene.BIMBSDDProperties
@@ -0,0 +1,65 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bsdd
import blenderbim.tool as tool
from blenderbim.core import bsdd as core
class LoadBSDDDomains(bpy.types.Operator):
bl_idname = "bim.load_bsdd_domains"
bl_label = "Load bSDD Dictionaries"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
core.load_bsdd(bsdd.Client(), tool.Bsdd)
return {"FINISHED"}
class SetActiveBSDDDictionary(bpy.types.Operator):
bl_idname = "bim.set_active_bsdd_domain"
bl_label = "Load bSDD Dictionary"
bl_options = {"REGISTER", "UNDO"}
name: bpy.props.StringProperty()
uri: bpy.props.StringProperty()
def execute(self, context):
core.set_active_bsdd_dictionary(self.name, self.uri, tool.Bsdd)
return {"FINISHED"}
class SearchBSDDClass(bpy.types.Operator):
bl_idname = "bim.search_bsdd_classifications"
bl_label = "Search bSDD Class"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
keyword = context.scene.BIMBSDDProperties.keyword
core.search_class(keyword, bsdd.Client(), tool.Bsdd)
return {"FINISHED"}
class GetBSDDClassificationProperties(bpy.types.Operator):
bl_idname = "bim.get_bsdd_classification_properties"
bl_label = "Search bSDD Classifications"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
core.get_class_properties(bsdd.Client(), tool.Bsdd)
return {"FINISHED"}
@@ -0,0 +1,67 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
from bpy.types import PropertyGroup
from blenderbim.bim.prop import Attribute, StrProperty
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
class BSDDDomain(PropertyGroup):
name: StringProperty(name="Name")
uri: StringProperty(name="URI")
default_language_code: StringProperty(name="Language")
organization_name_owner: StringProperty(name="Organization")
status: StringProperty(name="Status")
version: StringProperty(name="Version")
class BSDDClassification(PropertyGroup):
name: StringProperty(name="Name")
reference_code: StringProperty(name="Reference Code")
description: StringProperty(name="Description")
uri: StringProperty(name="Namespace URI")
domain_name: StringProperty(name="Domain Name")
domain_namespace_uri: StringProperty(name="Domain Namespace URI")
class BSDDPset(PropertyGroup):
name: StringProperty(name="Name")
properties: CollectionProperty(name="Properties", type=Attribute)
class BIMBSDDProperties(PropertyGroup):
active_domain: StringProperty(name="Active Domain")
active_uri: StringProperty(name="Active URI")
domains: CollectionProperty(name="Domains", type=BSDDDomain)
active_domain_index: IntProperty(name="Active Domain Index")
classifications: CollectionProperty(name="Classifications", type=BSDDClassification)
active_classification_index: IntProperty(name="Active Classification Index")
keyword: StringProperty(name="Keyword")
should_filter_ifc_class: BoolProperty(name="Filter Active IFC Class", default=True)
load_preview_domains: BoolProperty(name="Load Preview Domains", default=False)
classification_psets: CollectionProperty(name="Classification Psets", type=BSDDPset)
@@ -0,0 +1,79 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import blenderbim.tool as tool
from bpy.types import Panel, UIList
from blenderbim.bim.ifc import IfcStore
class BIM_PT_bsdd(Panel):
bl_label = "buildingSMART Data Dictionary"
bl_idname = "BIM_PT_bsdd"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_project_setup"
def draw(self, context):
props = context.scene.BIMBSDDProperties
row = self.layout.row(align=True)
row.prop(props, "load_preview_domains")
if len(props.domains):
row.operator("bim.load_bsdd_domains", text="", icon="FILE_REFRESH")
if props.active_domain:
row = self.layout.row()
row.label(text="Active: " + props.active_domain, icon="URL")
else:
row = self.layout.row()
row.label(text="No Active bSDD Domain", icon="ERROR")
if len(props.domains):
self.layout.template_list(
"BIM_UL_bsdd_domains",
"",
props,
"domains",
props,
"active_domain_index",
)
else:
row = self.layout.row()
row.operator("bim.load_bsdd_domains")
class BIM_UL_bsdd_domains(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item:
row = layout.row(align=True)
if item.status != "Active":
row.label(text=f"{item.name} ({item.organization_name_owner}) - {item.status}", icon="ERROR")
else:
row.label(text=f"{item.name} ({item.organization_name_owner})")
op = row.operator("bim.set_active_bsdd_domain", text="", icon="RESTRICT_SELECT_OFF")
op.name = item.name
op.uri = item.uri
class BIM_UL_bsdd_classifications(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item:
row = layout.row(align=True)
row.label(text=item.reference_code)
row.label(text=item.name)
@@ -24,6 +24,8 @@ import bpy_extras
import blenderbim.tool as tool
from mathutils import Vector, Matrix
from math import pi, radians, sin, cos, sqrt
import ifcopenshell.util.unit
messages = {
"SHARED_VERTEX": "Shared Vertex, no intersection possible",
@@ -140,6 +142,9 @@ class CadFillet(bpy.types.Operator):
layout.prop(self, prop)
def execute(self, context):
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
self.radius = self.radius * si_conversion
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.mode_set(mode="EDIT")
@@ -361,6 +366,10 @@ class CadOffset(bpy.types.Operator):
# dialog that Mesh Tools has. Sverchok is 2D based, but has a weird side
# effect of converting an unclosed loop into a closed loop which is also
# not what users expect.
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
self.distance = self.distance * si_conversion
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.mode_set(mode="EDIT")
@@ -498,6 +507,8 @@ class CadOffset(bpy.types.Operator):
local_direction = (rotation_i @ direction).normalized()
normals.append(local_direction)
if len(normals) == 2:
# https://stackoverflow.com/a/54042831/9627415
new_normal = (normals[0].lerp(normals[1], 0.5)).normalized()
@@ -531,7 +542,7 @@ class CadOffset(bpy.types.Operator):
class AddIfcCircle(bpy.types.Operator):
bl_idname = "bim.add_ifccircle"
bl_label = "Add IfcCircle"
radius: bpy.props.FloatProperty(name="Radius", default=0.1)
radius: bpy.props.FloatProperty(name="Radius", default=0.5)
@classmethod
def poll(cls, context):
@@ -539,6 +550,9 @@ class AddIfcCircle(bpy.types.Operator):
return bool(obj) and obj.type == "MESH"
def execute(self, context):
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
self.radius = self.radius * si_conversion
if self.has_selected_existing_circle(context):
self.change_radius(context)
else:
@@ -622,6 +636,9 @@ class AddIfcArcIndexFillet(bpy.types.Operator):
layout.prop(self, prop)
def execute(self, context):
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
self.radius = self.radius * si_conversion
if self.has_selected_existing_arc(context):
self.change_radius(context)
else:
@@ -786,8 +803,8 @@ class AlignViewToProfile(bpy.types.Operator):
class AddRectangle(bpy.types.Operator):
bl_idname = "bim.add_rectangle"
bl_label = "Add Rectangle"
x: bpy.props.FloatProperty(name="X", default=0.1)
y: bpy.props.FloatProperty(name="Y", default=0.1)
x: bpy.props.FloatProperty(name="X", default=1)
y: bpy.props.FloatProperty(name="Y", default=1)
@classmethod
def poll(cls, context):
@@ -795,6 +812,10 @@ class AddRectangle(bpy.types.Operator):
return bool(obj) and obj.type == "MESH"
def execute(self, context):
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
self.x = self.x * si_conversion
self.y = self.y * si_conversion
obj = context.active_object
bm = bmesh.from_edit_mesh(obj.data)
cursor = obj.matrix_world.inverted() @ context.scene.cursor.location
@@ -20,26 +20,33 @@ import bpy
from . import ui, prop, operator
classes = (
operator.AddClashSet,
operator.AddClashSource,
operator.ExecuteIfcClash,
operator.ExportClashSets,
operator.ImportClashSets,
operator.AddClashSet,
operator.LoadIfcClashes,
operator.SaveIfcClashes,
operator.LoadSmartGroupsForActiveClashSet,
operator.RemoveClashSet,
operator.AddClashSource,
operator.RemoveClashSource,
operator.SelectClashSource,
operator.ExecuteIfcClash,
operator.SelectIfcClashResults,
operator.SelectClash,
operator.SelectClashResults,
operator.SelectClashSource,
operator.SelectIfcClashResults,
operator.SelectSmartGroup,
operator.SelectSmartGroupedClashesPath,
operator.SmartClashGroup,
operator.SelectSmartGroup,
operator.LoadSmartGroupsForActiveClashSet,
prop.Clash,
prop.ClashSource,
prop.ClashSet,
prop.SmartClashGroup,
prop.BIMClashProperties,
ui.BIM_PT_ifcclash,
ui.BIM_PT_clash_manager,
ui.BIM_PT_dumb_clash_manager,
ui.BIM_PT_smart_clash_manager,
ui.BIM_UL_clashes,
ui.BIM_UL_clash_sets,
ui.BIM_UL_smart_groups,
)
@@ -26,6 +26,7 @@ import ifcopenshell
from mathutils import Matrix, Vector
from math import radians
from blenderbim.bim.ifc import IfcStore
import blenderbim.tool as tool
class ExportClashSets(bpy.types.Operator):
@@ -245,12 +246,14 @@ class ExecuteIfcClash(bpy.types.Operator):
y = Vector([y.x, y.y, y.z])
x = y.cross(z)
mat = Matrix([
[x[0], y[0], z[0], p.x],
[x[1], y[1], z[1], p.y],
[x[2], y[2], z[2], p.z],
[0, 0, 0, 0],
])
mat = Matrix(
[
[x[0], y[0], z[0], p.x],
[x[1], y[1], z[1], p.y],
[x[2], y[2], z[2], p.z],
[0, 0, 0, 0],
]
)
camera.matrix_world = mat
context.scene.camera = camera
@@ -336,12 +339,132 @@ class SelectIfcClashResults(bpy.types.Operator):
else:
element_file = self.file
element = element_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
if element.GlobalId in global_ids:
try:
element = element_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
except:
continue
global_id = getattr(element, "GlobalId", None)
if not global_id:
continue
if global_id in global_ids:
obj.select_set(True)
return {"FINISHED"}
class LoadIfcClashes(bpy.types.Operator):
bl_idname = "bim.load_ifc_clashes"
bl_label = "Load IFC Clashes"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Load the clashing IFC geometry stored in a file"
filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def invoke(self, context, event):
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context):
self.file = IfcStore.get_file()
self.filepath = bpy.path.ensure_ext(self.filepath, ".json")
with open(self.filepath) as f:
clash_sets_json = json.load(f)
active_clash_set = context.scene.BIMClashProperties.active_clash_set
for clash_set in clash_sets_json:
if not "clashes" in clash_set.keys():
self.report({"WARNING"}, "No clashes found for the selected Clash Set.")
return {"CANCELLED"}
active_clash_set.clashes.clear()
for clash in clash_set["clashes"].values():
blender_clash = active_clash_set.clashes.add()
blender_clash.a_global_id = clash["a_global_id"]
blender_clash.b_global_id = clash["b_global_id"]
blender_clash.a_name = "{}/{}".format(clash["a_ifc_class"], clash["a_name"])
blender_clash.b_name = "{}/{}".format(clash["b_ifc_class"], clash["b_name"])
blender_clash.status = False if not "status" in clash.keys() else clash["status"]
return {"FINISHED"}
class SaveIfcClashes(bpy.types.Operator):
bl_idname = "bim.save_ifc_clashes"
bl_label = "Save IFC Clashes"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Save the clashing IFC geometry stored in a file"
filename_ext = ".json"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def invoke(self, context, event):
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context):
self.file = IfcStore.get_file()
self.filepath = bpy.path.ensure_ext(self.filepath, ".json")
clash_sets_json = self.load_json()
active_clash_set = context.scene.BIMClashProperties.active_clash_set
self.update_clash_sets(clash_sets_json, active_clash_set)
self.save_json(clash_sets_json)
return {"FINISHED"}
def load_json(self):
with open(self.filepath) as f:
return json.load(f)
def update_clash_sets(self, clash_sets_json, active_clash_set):
for clash_set in clash_sets_json:
if clash_set["name"] != active_clash_set.name or "clashes" not in clash_set.keys():
continue
for clash in active_clash_set.clashes:
clash_key = clash.a_global_id + "-" + clash.b_global_id
if clash_set.get("clashes", {}).get(clash_key, None) is not None:
clash_set["clashes"][clash_key]["status"] = clash.status
def save_json(self, clash_sets_json):
with open(self.filepath, "w") as destination:
json.dump(clash_sets_json, destination, indent=4)
class SelectClash(bpy.types.Operator):
bl_idname = "bim.select_clash"
bl_label = "Select Clash"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Select the clashing IFC geometry stored in a file"
index: bpy.props.IntProperty()
def execute(self, context):
clash = context.scene.BIMClashProperties.active_clash
products = []
linked_objects = []
try:
products.append(tool.Ifc.get().by_guid(clash.a_global_id))
except:
linked_objects.append(clash.a_name)
try:
products.append(tool.Ifc.get().by_guid(clash.b_global_id))
except:
linked_objects.append(clash.b_name)
tool.Spatial.select_products(products, unhide=True)
print(linked_objects)
for obj_name in linked_objects:
obj = bpy.data.objects.get(obj_name)
if obj:
obj.select_set(True)
else:
print("Object not found:", obj_name)
if context.scene.BIMClashProperties.sould_focus_on_clash:
context_override = tool.Blender.get_viewport_context()
with bpy.context.temp_override(**context_override):
bpy.ops.view3d.view_selected()
return {"FINISHED"}
class SmartClashGroup(bpy.types.Operator):
bl_idname = "bim.smart_clash_group"
bl_label = "Smart Group Clashes"
@@ -426,9 +549,9 @@ class LoadSmartGroupsForActiveClashSet(bpy.types.Operator):
new_group = context.scene.BIMClashProperties.smart_clash_groups.add()
new_group.number = f"{smart_group}"
for pair in global_id_pairs:
for id in pair:
for guid in pair:
new_global_id = new_group.global_ids.add()
new_global_id.name = id
new_global_id.guid = guid
return {"FINISHED"}
@@ -443,20 +566,16 @@ class SelectSmartGroup(bpy.types.Operator):
return IfcStore.get_file() and context.visible_objects and context.scene.BIMClashProperties.active_smart_group
def execute(self, context):
self.file = IfcStore.get_file()
# Select smart group in view
selected_smart_group = context.scene.BIMClashProperties.active_smart_group
# print(selected_smart_group.number)
for obj in context.visible_objects:
if not obj.BIMObjectProperties.ifc_definition_id:
products = []
for global_id in selected_smart_group.global_ids:
try:
products.append(tool.Ifc.get().by_guid(global_id.guid))
except:
continue
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
for id in selected_smart_group.global_ids:
# print("Id: ", id)
# print("Global id: ", element.GlobalId)
if element.GlobalId in id.name:
# print("object match: ", global_id)
obj.select_set(True)
tool.Spatial.select_products(products, unhide=True)
context_override = tool.Blender.get_viewport_context()
with bpy.context.temp_override(**context_override):
bpy.ops.view3d.view_selected()
return {"FINISHED"}
@@ -43,11 +43,20 @@ class ClashSource(PropertyGroup):
)
class Clash(PropertyGroup):
a_global_id: StringProperty(name="A")
b_global_id: StringProperty(name="B")
a_name: StringProperty(name="A Name")
b_name: StringProperty(name="B Name")
status: BoolProperty(name="Status", default=False)
class ClashSet(PropertyGroup):
name: StringProperty(name="Name")
tolerance: FloatProperty(name="Tolerance")
a: CollectionProperty(name="Group A", type=ClashSource)
b: CollectionProperty(name="Group B", type=ClashSource)
clashes: CollectionProperty(name="Clashes", type=Clash)
class SmartClashGroup(PropertyGroup):
@@ -63,11 +72,13 @@ class BIMClashProperties(PropertyGroup):
clash_results_path: StringProperty(name="Clash Results Path")
smart_grouped_clashes_path: StringProperty(name="Smart Grouped Clashes Path")
active_clash_set_index: IntProperty(name="Active Clash Set Index")
active_clash_index: IntProperty(name="Active Clash Index")
smart_clash_groups: CollectionProperty(name="Smart Clash Groups", type=SmartClashGroup)
active_smart_group_index: IntProperty(name="Active Smart Group Index")
smart_clash_grouping_max_distance: IntProperty(
name="Smart Clash Grouping Max Distance", default=3, soft_min=1, soft_max=10
)
sould_focus_on_clash: BoolProperty(name="Show Focus Clash", default=False)
@property
def active_clash_set(self):
@@ -80,3 +91,9 @@ class BIMClashProperties(PropertyGroup):
if not self.smart_clash_groups:
return None
return self.smart_clash_groups[self.active_smart_group_index]
@property
def active_clash(self):
if not self.active_clash_set:
return None
return self.active_clash_set.clashes[self.active_clash_index]
@@ -107,6 +107,42 @@ class BIM_PT_clash_manager(Panel):
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_clash_detection"
def draw(self, context):
pass
class BIM_PT_dumb_clash_manager(Panel):
bl_idname = "BIM_PT_dumb_clash_manager"
bl_label = "Dumb Manager"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_clash_manager"
def draw(self, context):
layout = self.layout
props = context.scene.BIMClashProperties
row = layout.row(align=True)
row.operator("bim.load_ifc_clashes", text="LOAD IFC CLASHES", icon="IMPORT")
row.operator("bim.save_ifc_clashes", text="SAVE CLASH RESULTS", icon="EXPORT")
layout.template_list("BIM_UL_clashes", "", props.active_clash_set, "clashes", props, "active_clash_index")
# bim.select_clash
row = layout.row(align=True)
row.operator("bim.select_clash", text="SELECT CLASH", icon="IMPORT")
row.prop(props, "sould_focus_on_clash", icon="RESTRICT_VIEW_OFF")
class BIM_PT_smart_clash_manager(Panel):
bl_idname = "BIM_PT_smart_clash_manager"
bl_label = "Smart Clash Manager"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_clash_manager"
def draw(self, context):
layout = self.layout
props = context.scene.BIMClashProperties
@@ -156,3 +192,14 @@ class BIM_UL_smart_groups(bpy.types.UIList):
layout.label(text=str(item.number), translate=False, icon="NONE", icon_value=0)
else:
layout.label(text="", translate=False)
class BIM_UL_clashes(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item:
row = layout.row(align=True)
row.label(text=str(item.a_name), translate=False, icon="NONE", icon_value=0)
row.label(text=str(item.b_name), translate=False, icon="NONE", icon_value=0)
row.prop(item, "status", text="")
else:
layout.label(text="", translate=False)
@@ -21,13 +21,21 @@ from . import ui, prop, operator
classes = (
operator.AddClassification,
operator.AddClassificationFromBSDD,
operator.AddClassificationReference,
operator.AddClassificationReferenceFromBSDD,
operator.AddManualClassification,
operator.AddManualClassificationReference,
operator.ChangeClassificationLevel,
operator.DisableAddingManualClassification,
operator.DisableAddingManualClassificationReference,
operator.DisableEditingClassification,
operator.DisableEditingClassificationReference,
operator.DisableEditingClassificationReferences,
operator.EditClassification,
operator.EditClassificationReference,
operator.EnableAddingManualClassification,
operator.EnableAddingManualClassificationReference,
operator.EnableEditingClassification,
operator.EnableEditingClassificationReference,
operator.LoadClassificationLibrary,
@@ -73,6 +73,10 @@ class ReferencesData:
if name in [e.Name for e in tool.Ifc.get().by_type("IfcClassification")]:
return name
@classmethod
def classifications(cls):
return [(str(e.id()), e.Name, "") for e in tool.Ifc.get().by_type("IfcClassification")]
class ClassificationReferencesData(ReferencesData):
data = {}
@@ -83,6 +87,8 @@ class ClassificationReferencesData(ReferencesData):
cls.is_loaded = True
cls.data["references"] = cls.references()
cls.data["active_classification_library"] = cls.active_classification_library()
cls.data["classifications"] = cls.classifications()
cls.data["object_type"] = "OBJECT"
@classmethod
def references(cls):
@@ -105,6 +111,8 @@ class MaterialClassificationsData(ReferencesData):
cls.is_loaded = True
cls.data["references"] = cls.references()
cls.data["active_classification_library"] = cls.active_classification_library()
cls.data["classifications"] = cls.classifications()
cls.data["object_type"] = "MATERIAL"
@classmethod
def references(cls):
@@ -127,6 +135,8 @@ class CostClassificationsData(ReferencesData):
cls.is_loaded = True
cls.data["references"] = cls.references()
cls.data["active_classification_library"] = cls.active_classification_library()
cls.data["classifications"] = cls.classifications()
cls.data["object_type"] = "COST"
@classmethod
def references(cls):
@@ -54,6 +54,120 @@ class AddClassification(bpy.types.Operator, tool.Ifc.Operator):
)
class AddManualClassification(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_manual_classification"
bl_label = "Add Manual Classification"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMClassificationProperties
attributes = blenderbim.bim.helper.export_attributes(props.classification_attributes)
classification = ifcopenshell.api.run(
"classification.add_classification", tool.Ifc.get(), classification="Unnamed"
)
ifcopenshell.api.run(
"classification.edit_classification", tool.Ifc.get(), classification=classification, attributes=attributes
)
props.is_adding = False
class AddManualClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_manual_classification_reference"
bl_label = "Add Manual Classification Reference"
bl_options = {"REGISTER", "UNDO"}
obj_type: bpy.props.StringProperty()
def _execute(self, context):
obj = context.active_object
props = obj.BIMClassificationReferenceProperties
attributes = blenderbim.bim.helper.export_attributes(props.reference_attributes)
product = tool.Ifc.get_entity(obj)
# TODO: refactor and support material and cost item classifications
classification = tool.Ifc.get().by_id(int(props.classifications))
reference = ifcopenshell.api.run(
"classification.add_reference",
tool.Ifc.get(),
product=product,
classification=classification,
identification="X",
name="Unnamed",
)
ifcopenshell.api.run(
"classification.edit_reference", tool.Ifc.get(), reference=reference, attributes=attributes
)
props.is_adding = False
class AddClassificationFromBSDD(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_classification_from_bsdd"
bl_label = "Add Classification From bSDD"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMBSDDProperties
domain = [d for d in props.domains if d.name == props.active_domain][0]
for element in tool.Ifc.get().by_type("IfcClassification"):
if element.Name == props.active_domain or element.Location == domain.uri:
return
classification = ifcopenshell.api.run(
"classification.add_classification", tool.Ifc.get(), classification=props.active_domain
)
classification.Source = domain.organization_name_owner
classification.Location = domain.uri
classification.Edition = domain.version
class EnableAddingManualClassification(bpy.types.Operator):
bl_idname = "bim.enable_adding_manual_classification"
bl_label = "Enable Adding Manual Classification"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
props = context.scene.BIMClassificationProperties
props.is_adding = True
props.active_classification_id = 0
props.classification_attributes.clear()
blenderbim.bim.helper.import_attributes2("IfcClassification", props.classification_attributes)
return {"FINISHED"}
class DisableAddingManualClassification(bpy.types.Operator):
bl_idname = "bim.disable_adding_manual_classification"
bl_label = "Disable Adding Manual Classification"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
props = context.scene.BIMClassificationProperties
props.is_adding = False
return {"FINISHED"}
class EnableAddingManualClassificationReference(bpy.types.Operator):
bl_idname = "bim.enable_adding_manual_classification_reference"
bl_label = "Enable Adding Manual Classification Reference"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
obj = context.active_object
props = obj.BIMClassificationReferenceProperties
props.is_adding = True
props.reference_attributes.clear()
blenderbim.bim.helper.import_attributes2("IfcClassificationReference", props.reference_attributes)
return {"FINISHED"}
class DisableAddingManualClassificationReference(bpy.types.Operator):
bl_idname = "bim.disable_adding_manual_classification_reference"
bl_label = "Disable Adding Manual Classification Reference"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
obj = context.active_object
props = obj.BIMClassificationReferenceProperties
props.is_adding = False
return {"FINISHED"}
class EnableEditingClassification(bpy.types.Operator):
bl_idname = "bim.enable_editing_classification"
bl_label = "Enable Editing Classification"
@@ -175,21 +289,23 @@ class RemoveClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
else:
objects = [self.obj]
identification = tool.Ifc.get().by_id(self.reference)[0]
active_reference = tool.Ifc.get().by_id(self.reference)
identification = active_reference[1]
for obj in objects:
ifc_definition_id = blenderbim.bim.helper.get_obj_ifc_definition_id(context, obj, self.obj_type)
element = tool.Ifc.get().by_id(ifc_definition_id)
references = ifcopenshell.util.classification.get_references(element, should_inherit=False)
for reference in references:
if reference[0] == identification:
if (identification and reference[1] == identification) or (
not identification and reference == active_reference
):
ifcopenshell.api.run(
"classification.remove_reference",
tool.Ifc.get(),
reference=reference,
product=element,
)
break
class EditClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
@@ -254,6 +370,85 @@ class AddClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
)
class AddClassificationReferenceFromBSDD(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_classification_reference_from_bsdd"
bl_label = "Add Classification Reference From bSDD"
bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty()
obj_type: bpy.props.StringProperty()
def _execute(self, context):
if self.obj_type == "Object":
if context.selected_objects:
objects = [o.name for o in context.selected_objects]
else:
objects = [context.active_object.name]
else:
objects = [self.obj]
props = context.scene.BIMClassificationProperties
bprops = context.scene.BIMBSDDProperties
bsdd_classification = bprops.classifications[bprops.active_classification_index]
classification = None
for element in tool.Ifc.get().by_type("IfcClassification"):
if (
element.Name == bsdd_classification.domain_name
or element.Location == bsdd_classification.domain_namespace_uri
):
classification = element
break
if not classification:
classification = ifcopenshell.api.run(
"classification.add_classification", tool.Ifc.get(), classification=bsdd_classification.domain_name
)
classification.Location = bsdd_classification.domain_namespace_uri
for obj in objects:
ifc_definition_id = blenderbim.bim.helper.get_obj_ifc_definition_id(context, obj, self.obj_type)
if not ifc_definition_id:
continue
element = tool.Ifc.get().by_id(ifc_definition_id)
reference = ifcopenshell.api.run(
"classification.add_reference",
tool.Ifc.get(),
product=element,
classification=classification,
identification=bsdd_classification.reference_code,
name=bsdd_classification.name,
)
reference.Location = bsdd_classification.uri
for classification_pset in bprops.classification_psets:
is_pset = not classification_pset.name.startswith("Qto_")
if is_pset:
pset = ifcopenshell.util.element.get_pset(element, classification_pset.name, psets_only=True)
else:
pset = ifcopenshell.util.element.get_pset(element, classification_pset.name, qtos_only=True)
if pset:
pset = tool.Ifc.get().by_id(pset["id"])
elif is_pset:
pset = ifcopenshell.api.run(
"pset.add_pset", tool.Ifc.get(), product=element, name=classification_pset.name
)
else:
pset = ifcopenshell.api.run(
"pset.add_qto", tool.Ifc.get(), product=element, name=classification_pset.name
)
properties = {}
for prop in classification_pset.properties:
properties[prop.name] = prop.get_value()
if is_pset:
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties=properties)
else:
ifcopenshell.api.run("pset.edit_qto", tool.Ifc.get(), qto=pset, properties=properties)
class ChangeClassificationLevel(bpy.types.Operator):
bl_idname = "bim.change_classification_level"
bl_label = "Change Classification Level"
@@ -17,9 +17,10 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import blenderbim.bim.helper
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.module.classification.data import ClassificationsData
from blenderbim.bim.module.classification.data import ClassificationsData, ClassificationReferencesData
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
@@ -39,6 +40,12 @@ def get_available_classifications(self, context):
return ClassificationsData.data["available_classifications"]
def get_classifications(self, context):
if not ClassificationReferencesData.is_loaded:
ClassificationReferencesData.load()
return ClassificationReferencesData.data["classifications"]
class ClassificationReference(PropertyGroup):
name: StringProperty(name="Name")
identification: StringProperty(name="Identification")
@@ -48,6 +55,16 @@ class ClassificationReference(PropertyGroup):
class BIMClassificationProperties(PropertyGroup):
is_adding: BoolProperty(name="Is Adding", default=False)
classification_source: EnumProperty(
items=[
("FILE", "IFC File", ""),
("BSDD", "buildingSMART Data Dictionary", ""),
("MANUAL", "Manual Entry", ""),
],
name="Classification Source",
default="FILE",
)
available_classifications: EnumProperty(items=get_available_classifications, name="Available Classifications")
classification_attributes: CollectionProperty(name="Classification Attributes", type=Attribute)
active_classification_id: IntProperty(name="Active Classification Id")
@@ -57,5 +74,7 @@ class BIMClassificationProperties(PropertyGroup):
class BIMClassificationReferenceProperties(PropertyGroup):
is_adding: BoolProperty(name="Is Adding", default=False)
classifications: EnumProperty(items=get_classifications, name="Classifications")
reference_attributes: CollectionProperty(name="Reference Attributes", type=Attribute)
active_reference_id: IntProperty(name="Active Reference Id")
@@ -36,7 +36,7 @@ class BIM_PT_classifications(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_project_setup"
bl_parent_id = "BIM_PT_tab_project_setup"
@classmethod
def poll(cls, context):
@@ -48,6 +48,48 @@ class BIM_PT_classifications(Panel):
self.props = context.scene.BIMClassificationProperties
row = self.layout.row(align=True)
row.label(text="Source", icon="OUTLINER")
row.prop(self.props, "classification_source", text="")
if self.props.classification_source == "FILE":
self.draw_add_file_ui(context)
elif self.props.classification_source == "BSDD":
self.draw_add_bsdd_ui(context)
elif self.props.classification_source == "MANUAL":
self.draw_add_manual_ui(context)
for classification in ClassificationsData.data["classifications"]:
if self.props.active_classification_id == classification["id"]:
self.draw_editable_ui()
else:
self.draw_ui(classification)
def draw_add_manual_ui(self, context):
if self.props.is_adding:
blenderbim.bim.helper.draw_attributes(self.props.classification_attributes, self.layout)
row = self.layout.row(align=True)
row.operator("bim.add_manual_classification", text="Save", icon="CHECKMARK")
row.operator("bim.disable_adding_manual_classification", text="", icon="CANCEL")
else:
row = self.layout.row()
row.operator("bim.enable_adding_manual_classification", text="Add Classification", icon="ADD")
def draw_add_bsdd_ui(self, context):
self.bprops = context.scene.BIMBSDDProperties
if not self.bprops.active_domain:
row = self.layout.row()
row.label(text="No Active bSDD Domain", icon="ERROR")
return
row = self.layout.row()
row.label(text="Active: " + self.bprops.active_domain, icon="URL")
row = self.layout.row()
row.operator("bim.add_classification_from_bsdd", icon="ADD")
def draw_add_file_ui(self, context):
if ClassificationsData.data["has_classification_file"]:
row = self.layout.row(align=True)
row.prop(self.props, "available_classifications", text="")
@@ -58,12 +100,6 @@ class BIM_PT_classifications(Panel):
row.label(text="No Active Classification Library")
row.operator("bim.load_classification_library", text="", icon="IMPORT")
for classification in ClassificationsData.data["classifications"]:
if self.props.active_classification_id == classification["id"]:
self.draw_editable_ui()
else:
self.draw_ui(classification)
def draw_editable_ui(self):
row = self.layout.row(align=True)
row.operator("bim.edit_classification", text="Save changes", icon="CHECKMARK")
@@ -84,6 +120,7 @@ class ReferenceUI:
obj = context.active_object
self.oprops = obj.BIMObjectProperties
self.sprops = context.scene.BIMClassificationProperties
self.bprops = context.scene.BIMBSDDProperties
self.props = obj.BIMClassificationReferenceProperties
self.file = IfcStore.get_file()
@@ -100,14 +137,85 @@ class ReferenceUI:
self.draw_reference_ui(reference)
def draw_add_ui(self, context):
row = self.layout.row(align=True)
row.label(text="Source", icon="OUTLINER")
row.prop(self.sprops, "classification_source", text="")
if self.sprops.classification_source == "FILE":
self.draw_add_file_ui(context)
elif self.sprops.classification_source == "BSDD":
self.draw_add_bsdd_ui(context)
elif self.sprops.classification_source == "MANUAL":
self.draw_add_manual_ui(context)
def draw_add_manual_ui(self, context):
row = self.layout.row()
row.prop(self.props, "classifications", text="")
if self.props.is_adding:
blenderbim.bim.helper.draw_attributes(self.props.reference_attributes, self.layout)
row = self.layout.row(align=True)
op = row.operator("bim.add_manual_classification_reference", text="Save", icon="CHECKMARK")
op.type = self.data.data["object_type"]
row.operator("bim.disable_adding_manual_classification_reference", text="", icon="CANCEL")
else:
row = self.layout.row()
row.operator("bim.enable_adding_manual_classification_reference", text="Add Reference", icon="ADD")
def draw_add_bsdd_ui(self, context):
if not self.bprops.active_domain:
row = self.layout.row()
row.label(text="No Active bSDD Domain", icon="ERROR")
return
row = self.layout.row()
row.label(text="Active: " + self.bprops.active_domain, icon="URL")
row = self.layout.row(align=True)
row.prop(self.bprops, "keyword", text="")
row.operator("bim.search_bsdd_classifications", text="", icon="VIEWZOOM")
row = self.layout.row()
row.prop(self.bprops, "should_filter_ifc_class")
if len(self.bprops.classifications):
self.layout.template_list(
"BIM_UL_bsdd_classifications",
"",
self.bprops,
"classifications",
self.bprops,
"active_classification_index",
)
else:
row = self.layout.row()
row.label(text="No Search Results")
if self.bprops.active_classification_index < len(self.bprops.classifications):
row = self.layout.row(align=True)
op = row.operator(
"bim.add_classification_reference_from_bsdd", text="Add Classification Reference", icon="ADD"
)
op.obj = self.obj
op.obj_type = self.obj_type
row.operator("bim.get_bsdd_classification_properties", text="", icon="COPY_ID")
if len(self.bprops.classification_psets):
for pset in self.bprops.classification_psets:
box = self.layout.box()
row = box.row()
row.label(text=pset.name, icon="COPY_ID")
blenderbim.bim.helper.draw_attributes(pset.properties, box)
def draw_add_file_ui(self, context):
if not self.data.data["active_classification_library"]:
row = self.layout.row(align=True)
row.label(text="No Active Classification Library")
row.label(text="No Active Classification Library", icon="ERROR")
row.operator("bim.load_classification_library", text="", icon="IMPORT")
return
row = self.layout.row(align=True)
row.label(text=f"Active Classification Library: {self.data.data['active_classification_library']}")
#row.prop(self.sprops, "available_classifications", text="")
# row.prop(self.sprops, "available_classifications", text="")
if not self.sprops.available_library_references:
op = row.operator("bim.change_classification_level", text="", icon="GREASEPENCIL")
op.parent_id = int(self.sprops.available_classifications)
@@ -146,6 +254,8 @@ class ReferenceUI:
name = reference["Identification"] or "No Identification"
row.label(text=name, icon="ASSET_MANAGER")
row.label(text=reference["Name"] or "")
if reference["Location"]:
row.operator("bim.open_uri", icon="URL", text="").uri = reference["Location"]
if not self.props.active_reference_id:
op = row.operator("bim.enable_editing_classification_reference", text="", icon="GREASEPENCIL")
op.reference = reference["id"]
@@ -1,124 +0,0 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import os
import logging
import ifcopenshell
import json
import webbrowser
import tempfile
from blenderbim.bim.ifc import IfcStore
class SelectCobieIfcFile(bpy.types.Operator):
bl_idname = "bim.select_cobie_ifc_file"
bl_label = "Select COBie IFC File"
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
context.scene.COBieProperties.cobie_ifc_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectCobieJsonFile(bpy.types.Operator):
bl_idname = "bim.select_cobie_json_file"
bl_label = "Select COBie JSON File"
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
context.scene.COBieProperties.cobie_json_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcCobie(bpy.types.Operator):
bl_idname = "bim.execute_ifc_cobie"
bl_label = "Execute IFCCOBie"
file_format: bpy.props.StringProperty()
@classmethod
def poll(cls, context):
props = context.scene.COBieProperties
return props.should_load_from_memory or props.cobie_ifc_file
def execute(self, context):
from cobie import IfcCobieParser
props = context.scene.COBieProperties
if props.should_load_from_memory:
output_dir = tempfile.gettempdir()
else:
output_dir = os.path.dirname(props.cobie_ifc_file)
output = os.path.join(output_dir, "output")
logger = logging.getLogger("IFCtoCOBie")
fh = logging.FileHandler(os.path.join(output_dir, "cobie.log"))
fh.setLevel(logging.DEBUG)
fh.setFormatter(logging.Formatter("%(asctime)s : %(levelname)s : %(message)s"))
logger = logging.getLogger("IFCtoCOBie")
logger.addHandler(fh)
selector = ifcopenshell.util.selector.Selector()
if props.cobie_json_file:
with open(props.cobie_json_file, "r") as f:
custom_data = json.load(f)
else:
custom_data = {}
parser = IfcCobieParser(logger, selector)
ifc_file = IfcStore.get_file()
if not (ifc_file and props.should_load_from_memory):
ifc_file = props.cobie_ifc_file
parser.parse(
ifc_file,
props.cobie_types,
props.cobie_components,
custom_data,
)
if self.file_format == "xlsx":
from cobie import CobieXlsWriter
writer = CobieXlsWriter(parser, output)
writer.write()
webbrowser.open("file://" + output + "." + self.file_format)
elif self.file_format == "ods":
from cobie import CobieOdsWriter
writer = CobieOdsWriter(parser, output)
writer.write()
webbrowser.open("file://" + output + "." + self.file_format)
else:
from cobie import CobieCsvWriter
writer = CobieCsvWriter(parser, output_dir)
writer.write()
webbrowser.open("file://" + output_dir)
webbrowser.open("file://" + output_dir + "/cobie.log")
return {"FINISHED"}
@@ -29,7 +29,7 @@ class BIM_PT_constraints(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_project_setup"
bl_parent_id = "BIM_PT_tab_project_setup"
@classmethod
def poll(cls, context):
@@ -29,7 +29,7 @@ class BIM_PT_context(bpy.types.Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_geometry"
bl_parent_id = "BIM_PT_tab_geometry"
@classmethod
def poll(cls, context):
@@ -136,13 +136,11 @@ class CostSchedulesData:
data["UnitBasisUnitSymbol"] = "U"
if cost_value.Category == "*":
is_sum = True
cost_quantity = data["TotalCostQuantity"] or 1
if has_unit_basis:
data["TotalCost"] = data["TotalAppliedValue"] / data["UnitBasisValueComponent"]
data["TotalCost"] = data["TotalAppliedValue"] * cost_quantity / data["UnitBasisValueComponent"]
else:
if data["TotalCostQuantity"] is not None:
data["TotalCost"] = data["TotalAppliedValue"] * data["TotalCostQuantity"]
else:
data["TotalCost"] = data["TotalAppliedValue"]
data["TotalCost"] = data["TotalAppliedValue"] * cost_quantity
if is_sum:
data["TotalAppliedValue"] = None
@@ -160,8 +158,10 @@ class CostSchedulesData:
unit = ifcopenshell.util.unit.get_property_unit(quantity, tool.Ifc.get())
if unit:
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
else:
data["UnitSymbol"] = "U"
if quantity.is_a("IfcPhysicalSimpleQuantity"):
measure_class = quantity.wrapped_data.declaration().as_entity().attribute_by_index(3).type_of_attribute().declared_type().name()
if "Count" in measure_class:
data["UnitSymbol"] = "U"
# same_unit_nested_cost_item = set()
# data["DerivedTotalCostQuantity"] = None
@@ -256,7 +256,7 @@ class CostSchedulesData:
for cost_value in cost_item.CostValues or []:
label = "{0:.2f}".format(ifcopenshell.util.cost.calculate_applied_value(cost_item, cost_value))
label += " = {}".format(ifcopenshell.util.cost.serialise_cost_value(cost_value))
results.append({"id": cost_value.id(), "label": label})
results.append({"id": cost_value.id(), "label": label, "name": cost_value.Name})
return results
@classmethod
@@ -37,12 +37,10 @@ class AddCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
object_type: bpy.props.StringProperty()
def _execute(self, context):
core.add_cost_schedule(
tool.Ifc,
name=self.name,
predefined_type=context.scene.BIMCostProperties.cost_schedule_predefined_types,
object_type=self.object_type,
)
predefined_type = context.scene.BIMCostProperties.cost_schedule_predefined_types
if predefined_type == "USERDEFINED":
predefined_type = self.object_type
core.add_cost_schedule(tool.Ifc, name=self.name, predefined_type=predefined_type)
def draw(self, context):
layout = self.layout
@@ -42,19 +42,21 @@ class BIM_PT_cost_schedules(Panel):
CostSchedulesData.load()
self.props = context.scene.BIMCostProperties
row = self.layout.row(align=True)
if not self.props.active_cost_schedule_id:
row = self.layout.row(align=True)
if CostSchedulesData.data["total_cost_schedules"]:
row.alignment = "RIGHT"
row.operator("bim.export_cost_schedules",icon="EXPORT",text="Export All Schedules")
row = self.layout.row(align=True)
row.label(text=f"{CostSchedulesData.data['total_cost_schedules']} Cost Schedules Found", icon="TEXT")
else:
row.label(text="No Cost Schedules found.", icon="TEXT")
row.operator("bim.add_cost_schedule", icon="ADD", text="")
row.operator("import_cost_schedule_csv.bim",icon="IMPORT",text="")
for schedule in CostSchedulesData.data["schedules"]:
self.draw_cost_schedule_ui(schedule)
row2 = self.layout.row()
row2.alignment = "RIGHT"
row2.operator("bim.export_cost_schedules", text="Export all", icon="EXPORT")
def draw_cost_schedule_ui(self, cost_schedule):
row = self.layout.row(align=True)
@@ -236,6 +238,8 @@ class BIM_PT_cost_schedules(Panel):
blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, self.layout.box())
def draw_readonly_cost_value_ui(self, layout, cost_value):
if cost_value["name"]:
layout.label(text=f"{cost_value['name']}: ")
if self.props.active_cost_value_id == cost_value["id"] and self.props.cost_value_editing_type == "FORMULA":
layout.prop(self.props, "cost_value_formula", text="")
else:
@@ -0,0 +1,41 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import prop, workspace
classes = (
prop.BIMCoveringProperties,
workspace.Hotkey,
)
def register():
if not bpy.app.background:
bpy.utils.register_tool(workspace.CoveringTool, after={"bim.structural_tool"}, separator=False, group=False)
bpy.types.Scene.BIMCoveringProperties = bpy.props.PointerProperty(type=prop.BIMCoveringProperties)
# bpy.types.Object.BIMObjectSpatialProperties = bpy.props.PointerProperty(type=prop.BIMObjectSpatialProperties)
# bpy.types.Scene.BIMSpatialManagerProperties = bpy.props.PointerProperty(type=prop.BIMSpatialManagerProperties)
def unregister():
if not bpy.app.background:
bpy.utils.unregister_tool(workspace.CoveringTool)
del bpy.types.Scene.BIMCoveringProperties
# del bpy.types.Object.BIMObjectSpatialProperties
# del bpy.types.Scene.BIMSpatialManagerProperties
@@ -17,8 +17,8 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
from blenderbim.bim.module.lca.data import LcaData
from blenderbim.bim.prop import StrProperty, Attribute
#from blenderbim.bim.module.spatial.data import SpatialData
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
@@ -30,15 +30,10 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
#import blenderbim.tool as tool
#import blenderbim.core.geometry
#import ifcopenshell
def get_product_systems(self, context):
if not LcaData.is_loaded:
LcaData.load()
return LcaData.data["product_systems"]
class BIMLCAProperties(PropertyGroup):
is_connected: BoolProperty(name="Is Connected")
amount: FloatProperty(name="Amount")
product_systems: EnumProperty(items=get_product_systems, name="Product Systems")
class BIMCoveringProperties(PropertyGroup):
ceiling_height: bpy.props.FloatProperty(name="ceiling_height", default=2.7, subtype="DISTANCE", description="Ceiling height")
@@ -0,0 +1,272 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2023 @Andrej730
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import os
import bpy
import ifcopenshell
import blenderbim.tool as tool
from blenderbim.bim.helper import prop_with_search
from blenderbim.bim.module.model.data import AuthoringData
from bpy.types import WorkSpaceTool
from blenderbim.bim.ifc import IfcStore
import blenderbim.bim.handler
# declaring it here to avoid circular import problems
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class CoveringTool(WorkSpaceTool):
bl_space_type = "VIEW_3D"
bl_context_mode = "OBJECT"
bl_idname = "bim.covering_tool"
bl_label = "Covering Tool"
bl_description = "Create and edit coverings"
bl_icon = os.path.join(os.path.dirname(__file__), "ops.authoring.covering")
bl_widget = None
ifc_element_type = "IfcCoveringType"
bl_keymap = tool.Blender.get_default_selection_keypmap() + (
("bim.covering_hotkey", {"type": "A", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_A")]}),
("bim.covering_hotkey", {"type": "G", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_G")]}),
)
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CoveringToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
def add_layout_hotkey(layout, text, hotkey, description):
args = ["covering", layout, text, hotkey, description]
tool.Blender.add_layout_hotkey_operator(*args)
class CoveringToolUI:
@classmethod
def draw(cls, context, layout, ifc_element_type = None):
cls.layout = layout
cls.props = context.scene.BIMModelProperties
cls.covering_props = context.scene.BIMCoveringProperties
row = cls.layout.row(align=True)
if not tool.Ifc.get():
row.label(text="No IFC Project", icon="ERROR")
return
if not AuthoringData.is_loaded:
AuthoringData.load(ifc_element_type)
elif AuthoringData.data["ifc_element_type"] != ifc_element_type:
AuthoringData.load(ifc_element_type)
if context.region.type == "TOOL_HEADER":
cls.draw_header_interface()
elif context.region.type in ("UI", "WINDOW"):
cls.draw_basic_bim_tool_interface()
cls.draw_default_interface()
@classmethod
def draw_header_interface(cls):
cls.draw_type_selection_interface()
@classmethod
def draw_default_interface(cls):
row = cls.layout.row(align=True)
row.prop(data=cls.props, property="rl3", text="RL")
row = cls.layout.row(align=True)
row.prop(data=cls.covering_props, property="ceiling_height", text="Ceiling Height")
if AuthoringData.data["ifc_classes"]:
active_obj = bpy.context.active_object
element = tool.Ifc.get_entity(active_obj)
collection = bpy.context.view_layer.active_layer_collection.collection
collection_obj = collection.BIMCollectionProperties.obj
relating_type_id = int(cls.props.relating_type_id)
type_material_usage = ifcopenshell.util.element.get_material(tool.Ifc.get().by_id(relating_type_id)).is_a()
# PLEASE KEEP COMMENTS AS A REMINDER
# elif element and bpy.context.selected_objects and element.is_a("IfcSpace"):
# op. = row.operator("bim.add_istance_flooring_from_spaces"):
if (type_material_usage == "IfcMaterialLayerSet" and
not bpy.context.selected_objects):
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
if tool.Ifc.get_entity(collection_obj):
if AuthoringData.data["predefined_type"] == "FLOORING":
op = row.operator("bim.add_instance_flooring_covering_from_cursor")
elif AuthoringData.data["predefined_type"] == "CEILING":
op = row.operator("bim.add_instance_ceiling_covering_from_cursor")
else:
op = row.operator("bim.add_constr_type_instance", text="Add")
op.from_invoke = True
if cls.props.relating_type_id.isnumeric():
op.relating_type_id = int(cls.props.relating_type_id)
else:
op = row.operator("bim.add_constr_type_instance", text="Add")
op.from_invoke = True
if cls.props.relating_type_id.isnumeric():
op.relating_type_id = int(cls.props.relating_type_id)
elif (AuthoringData.data["predefined_type"] == "FLOORING" and
type_material_usage == "IfcMaterialLayerSet" and
element and
bpy.context.selected_objects and
element.is_a("IfcWall")):
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
op = row.operator("bim.add_instance_flooring_coverings_from_walls")
elif (AuthoringData.data["predefined_type"] == "CEILING" and
type_material_usage == "IfcMaterialLayerSet" and
element and
bpy.context.selected_objects and
element.is_a("IfcWall")):
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
op = row.operator("bim.add_instance_ceiling_coverings_from_walls")
elif (element and
bpy.context.selected_objects and
element.is_a("IfcCovering") and
# AuthoringData.data["predefined_type"] == "FLOORING" and
AuthoringData.data["active_material_usage"] == "LAYER3"):
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_G")
op = row.operator("bim.regen_selected_covering_object")
# elif AuthoringData.data["predefined_type"] == "CEILING":
# row = cls.layout.row(align=True)
# row.prop(data=cls.props, property="ceiling_height", text="ceiling height")
# if element and bpy.context.selected_objects and element.is_a("IfcWall"):
# op = row.operator("bim.add_instance_ceiling_coverings_from_walls")
# elif element and bpy.context.selected_objects and element.is_a("IfcSpace"):
# op. = row.operator("bim.add_istance_flooring_from_spaces"):
# else:
# op = row.operator("bim.add_instance_ceiling_from_cursor")
# op = row.operator("bim.add_constr_type_instance", text="Add")
# op.from_invoke = True
# if cls.props.relating_type_id.isnumeric():
# op.relating_type_id = int(cls.props.relating_type_id)
else:
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
op = row.operator("bim.add_constr_type_instance", text="Add")
op.from_invoke = True
if cls.props.relating_type_id.isnumeric():
op.relating_type_id = int(cls.props.relating_type_id)
@classmethod
def draw_type_selection_interface(cls):
# shared by both sidebar and header
row = cls.layout.row(align=True)
if AuthoringData.data["ifc_classes"]:
row = cls.layout.row(align=True)
row.label(text="", icon="FILE_3D")
prop_with_search(row, cls.props, "relating_type_id", text="")
row.operator("bim.launch_type_manager", icon="LIGHTPROBE_GRID", text="")
else:
row.label(text=f"No {AuthoringData.data['ifc_element_type']} Found", icon="ERROR")
row = cls.layout.row()
row.operator("bim.launch_type_manager", icon="LIGHTPROBE_GRID", text="Launch Type Manager")
@classmethod
def draw_basic_bim_tool_interface(cls):
cls.draw_type_selection_interface()
if AuthoringData.data["ifc_classes"]:
if cls.props.ifc_class:
box = cls.layout.box()
if AuthoringData.data["type_thumbnail"]:
box.template_icon(icon_value=AuthoringData.data["type_thumbnail"], scale=5)
else:
op = box.operator("bim.load_type_thumbnails", text="Load Thumbnails", icon="FILE_REFRESH")
op.ifc_class = cls.props.ifc_class
class Hotkey(bpy.types.Operator, Operator):
bl_idname = "bim.covering_hotkey"
bl_label = "Hotkey"
bl_options = {"REGISTER", "UNDO"}
hotkey: bpy.props.StringProperty()
description: bpy.props.StringProperty()
@classmethod
def poll(cls, context):
return tool.Ifc.get()
@classmethod
def description(cls, context, operator):
return operator.description or ""
def _execute(self, context):
# self.props = context.scene.BIMCoveringProperties
getattr(self, f"hotkey_{self.hotkey}")()
def invoke(self, context, event):
# https://blender.stackexchange.com/questions/276035/how-do-i-make-operators-remember-their-property-values-when-called-from-a-hotkey
# self.props = context.scene.BIMSpatialProperties
return self.execute(context)
def draw(self, context):
pass
def hotkey_S_A(self):
active_obj = bpy.context.active_object
element = tool.Ifc.get_entity(active_obj)
collection = bpy.context.view_layer.active_layer_collection.collection
collection_obj = collection.BIMCollectionProperties.obj
if AuthoringData.data["predefined_type"] == "FLOORING":
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
bpy.ops.bim.add_instance_flooring_coverings_from_walls()
elif tool.Ifc.get_entity(collection_obj):
bpy.ops.bim.add_instance_flooring_covering_from_cursor()
else:
bpy.ops.bim.add_constr_type_instance()
elif AuthoringData.data["predefined_type"] == "CEILING":
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
bpy.ops.bim.add_instance_ceiling_coverings_from_walls()
elif tool.Ifc.get_entity(collection_obj):
bpy.ops.bim.add_instance_ceiling_covering_from_cursor()
else:
bpy.ops.bim.add_constr_type_instance()
else:
bpy.ops.bim.add_constr_type_instance()
def hotkey_S_G(self):
active_obj = bpy.context.active_object
element = tool.Ifc.get_entity(active_obj)
if (element and
bpy.context.selected_objects and
element.is_a("IfcCovering") and
AuthoringData.data["active_material_usage"] == "LAYER3"):
bpy.ops.bim.regen_selected_covering_object()
@@ -22,11 +22,11 @@ import json
import ifccsv
import logging
import tempfile
import webbrowser
import ifcopenshell
import blenderbim.tool as tool
import blenderbim.bim.module.drawing.scheduler as scheduler
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.handler import purge_module_data
from blenderbim.bim.handler import refresh_ui_data
class AddCsvAttribute(bpy.types.Operator):
@@ -93,15 +93,26 @@ class ImportCsvAttributes(bpy.types.Operator):
data = json.load(open(self.filepath))
tool.Search.import_filter_query(data["query"], props.filter_groups)
for prop in [
"should_generate_svg",
"should_preserve_existing",
"include_global_id",
"null_value",
"empty_value",
"true_value",
"false_value",
"concat_value",
"csv_delimiter",
"format",
"csv_custom_delimiter",
]:
setattr(props, prop, data["settings"][prop])
props.csv_attributes.clear()
for attribute in data["attributes"]:
new = props.csv_attributes.add()
new.name = attribute["name"]
new.header = attribute["header"]
new.sort = attribute["sort"]
new.group = attribute["group"]
new.summary = attribute["summary"]
new.formatting = attribute["formatting"]
for prop in ["name", "header", "sort", "group", "summary", "formatting"]:
setattr(new, prop, attribute[prop])
return {"FINISHED"}
def invoke(self, context, event):
@@ -121,6 +132,22 @@ class ExportCsvAttributes(bpy.types.Operator):
def execute(self, context):
props = context.scene.CsvProperties
settings = {}
for prop in [
"should_generate_svg",
"should_preserve_existing",
"include_global_id",
"null_value",
"empty_value",
"true_value",
"false_value",
"concat_value",
"csv_delimiter",
"format",
"csv_custom_delimiter",
]:
settings[prop] = getattr(props, prop)
data = {
"query": tool.Search.export_filter_query(props.filter_groups),
"attributes": [
@@ -134,6 +161,7 @@ class ExportCsvAttributes(bpy.types.Operator):
}
for a in props.csv_attributes
],
"settings": settings,
}
with open(self.filepath, "w") as outfile:
@@ -208,11 +236,16 @@ class ExportIfcCsv(bpy.types.Operator):
empty=props.empty_value,
bool_true=props.true_value,
bool_false=props.false_value,
concat=props.concat_value,
sort=sort,
groups=groups,
summaries=summaries,
formatting=formatting,
)
if props.format != "csv" and props.should_generate_svg:
schedule_creator = scheduler.Scheduler()
schedule_creator.schedule(self.filepath, tool.Drawing.get_path_with_ext(self.filepath, "svg"))
return {"FINISHED"}
@@ -251,7 +284,7 @@ class ImportIfcCsv(bpy.types.Operator):
)
if not props.should_load_from_memory:
ifc_file.write(props.csv_ifc_file)
purge_module_data()
refresh_ui_data()
return {"FINISHED"}
@@ -17,8 +17,7 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
from blenderbim.bim.module.search.prop import BIMFilterGroup
from blenderbim.bim.prop import StrProperty
from blenderbim.bim.prop import StrProperty, BIMFilterGroup
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
@@ -66,12 +65,14 @@ class CsvProperties(PropertyGroup):
ifc_selector: StringProperty(default="", name="IFC Selector")
filter_groups: CollectionProperty(type=BIMFilterGroup, name="Filter Groups")
csv_attributes: CollectionProperty(name="CSV Attributes", type=CsvAttribute)
should_generate_svg: BoolProperty(default=False, name="Generate SVG")
should_preserve_existing: BoolProperty(default=False, name="Preserve Existing")
include_global_id: BoolProperty(default=True, name="Include GlobalId")
null_value: StringProperty(default="N/A", name="Null Value")
empty_value: StringProperty(default="-", name="Empty String Value")
true_value: StringProperty(default="YES", name="True Value")
false_value: StringProperty(default="NO", name="False Value")
concat_value: StringProperty(default=", ", name="Concat Value")
csv_delimiter: EnumProperty(
items=[
(";", ";", ""),
@@ -67,6 +67,8 @@ class BIM_PT_ifccsv(Panel):
row = layout.row(align=True)
row.prop(props, "csv_custom_delimiter")
row = layout.row()
row.prop(props, "should_generate_svg")
row = layout.row()
row.prop(props, "should_preserve_existing")
row = layout.row()
@@ -79,9 +81,11 @@ class BIM_PT_ifccsv(Panel):
row.prop(props, "true_value")
row = layout.row()
row.prop(props, "false_value")
row = layout.row()
row.prop(props, "concat_value")
layout.use_property_split = False
blenderbim.bim.helper.draw_filter(self.layout, props, SearchData, "csv")
blenderbim.bim.helper.draw_filter(self.layout, props.filter_groups, SearchData, "csv")
row = layout.row(align=True)
row.operator("bim.add_csv_attribute", icon="ADD")
@@ -20,23 +20,26 @@ import bpy
from . import ui, prop, operator
classes = (
operator.ConvertToBlender,
operator.CopyDebugInformation,
operator.CreateAllShapes,
operator.CreateShapeFromStepId,
operator.InspectFromObject,
operator.InspectFromStepId,
operator.OverrideDisplayType,
operator.ParseExpress,
operator.PrintIfcFile,
operator.PrintObjectPlacement,
operator.ProfileImportIFC,
operator.PurgeHdf5Cache,
operator.PurgeIfcLinks,
operator.ConvertToBlender,
operator.RewindInspector,
operator.SelectExpressFile,
operator.SelectHighPolygonMeshes,
operator.SelectHighestPolygonMeshes,
operator.ValidateIfcFile,
operator.PrintUnusedElementStats,
operator.PurgeUnusedElementsByClass,
prop.BIMDebugProperties,
ui.BIM_PT_debug,
)
@@ -116,7 +116,7 @@ class PurgeIfcLinks(bpy.types.Operator):
context.scene.BIMProperties.ifc_file = ""
context.scene.BIMDebugProperties.attributes.clear()
IfcStore.purge()
blenderbim.bim.handler.purge_module_data()
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
@@ -136,7 +136,7 @@ class ConvertToBlender(bpy.types.Operator):
m.BIMMaterialProperties.ifc_style_id = False
bpy.context.scene.BIMProperties.ifc_file = ""
IfcStore.purge()
blenderbim.bim.handler.purge_module_data()
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
@@ -146,16 +146,33 @@ class ValidateIfcFile(bpy.types.Operator):
@classmethod
def poll(cls, context):
return IfcStore.get_file()
return tool.Ifc.get()
def execute(self, context):
import ifcopenshell.validate
class LogDetectionHandler(logging.Handler):
message_logged = False
def emit(self, record):
if not self.message_logged:
self.message_logged = True
logger = logging.getLogger("validate")
logger.setLevel(logging.DEBUG)
ifcopenshell.validate.validate(IfcStore.get_file(), logger, express_rules=True)
self.report({"INFO"}, "Check validation results in the system console.")
# use LogDetectionHandler to check whether there were any validation errors
# during `ifcopenshell.validate.validate`
handler = LogDetectionHandler()
logger.addHandler(handler)
ifcopenshell.validate.validate(tool.Ifc.get(), logger, express_rules=True)
logger.removeHandler(handler)
if handler.message_logged:
self.report({"INFO"}, "Check validation results in the system console.")
else:
self.report({"INFO"}, "No validation issues found.")
return {"FINISHED"}
@@ -196,7 +213,7 @@ class CreateAllShapes(bpy.types.Operator):
settings_2d.set(settings_2d.INCLUDE_CURVES, True)
failures = []
excludes = () # For the developer to debug with
for i, element in enumerate(elements):
for i, element in enumerate(elements, 1):
if element.GlobalId in excludes:
continue
print(f"{i}/{total}:", element)
@@ -218,7 +235,7 @@ class CreateAllShapes(bpy.types.Operator):
len(shape.geometry.edges),
len(shape.geometry.faces),
)
print(f"Failures: {len(failures)}")
self.report({"INFO"}, f"Failed shapes: {len(failures)}, check the system console for details.")
for failure in failures:
print(failure)
return {"FINISHED"}
@@ -443,3 +460,166 @@ class PurgeHdf5Cache(bpy.types.Operator):
def execute(self, context):
core.purge_hdf5_cache(tool.Debug)
return {"FINISHED"}
class OverrideDisplayType(bpy.types.Operator):
bl_idname = "bim.override_display_type"
bl_label = "Override Display Type"
display: bpy.props.StringProperty()
def execute(self, context):
for obj in context.selected_objects:
obj.display_type = self.display
return {"FINISHED"}
class PrintUnusedElementStats(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.print_unused_elements_stats"
bl_label = "Print Unused Elements Stats"
bl_options = {"REGISTER", "UNDO"}
bl_description = (
"Print all unused elements in current IFC project in system console, not limited to the selected class"
)
ignore_contexts: bpy.props.BoolProperty(name="Ignore Contexts", default=True)
ignore_relationships: bpy.props.BoolProperty(name="Ignore Relationships", default=True)
ignore_types: bpy.props.BoolProperty(name="Ignore Types", default=True)
ignore_styled_items: bpy.props.BoolProperty(name="Ignoer Styled Items", default=True)
def _execute(self, context):
props = context.scene.BIMDebugProperties
# ignore some classes that could have zero 0 inverse references by their nature
ignore_classes = []
if self.ignore_contexts:
ignore_classes += ["IfcRepresentationContext"]
if self.ignore_relationships:
ignore_classes += ["IfcRelationship"]
if self.ignore_types:
ignore_classes += ["IfcTypeProduct"]
if self.ignore_styled_items:
ignore_classes += ["IfcStyledItem"]
unused_elements = tool.Debug.print_unused_elements_stats(props.ifc_class_purge, ignore_classes)
self.report({"INFO"}, f"{unused_elements} unused elements found, check the system console for the details.")
class PurgeUnusedElementsByClass(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.purge_unused_elements_by_class"
bl_label = "Purge Unused Elements By Class"
bl_description = (
"Will find all elements of class that have no inverse refernces and will remove them, use very carefully"
)
bl_options = {"REGISTER", "UNDO"}
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def _execute(self, context):
props = context.scene.BIMDebugProperties
if props.ifc_class_purge:
purged_elements = core.purge_unused_elements(tool.Ifc, tool.Debug, props.ifc_class_purge)
self.report({"INFO"}, f"{purged_elements} unused elements found and removed.")
tool.Ifc.get().write(self.filepath)
return
# A whitelisted class is a class that only contains simple data that
# has no meaning by itself (only has meaning when combined with other
# data). E.g. a colour by itself has no meaning so is whitelisted, but
# a material by itself may be part of your materials library.
# There are classes I don't know enough about to decide. Not whitelisting in case.
# IfcAlignmentParameterSegment
# IfcBoundaryCondition
# IfcStructuralConnectionCondition
# IfcStructuralLoad
whitelisted_classes = [
"IfcActorRole",
"IfcAddress",
"IfcApplication",
"IfcAppliedValue",
"IfcConnectionGeometry",
"IfcCoordinateReferenceSystem",
"IfcDerivedUnit",
"IfcDerivedUnitElement",
"IfcDimensionalExponents",
"IfcExternalReference",
"IfcGridAxis",
"IfcIrregularTimeSeriesValue",
"IfcLightDistributionData",
"IfcLightIntensityDistribution",
"IfcMeasureWithUnit",
"IfcMonetaryUnit",
"IfcNamedUnit",
"IfcObjectPlacement",
"IfcOrganization", # Should be referenced as part of an actor
"IfcOwnerHistory",
"IfcPerson", # Should be referenced as part of an actor
"IfcPersonAndOrganization", # Should be referenced as part of an actor
"IfcPhysicalQuantity",
"IfcPresentationItem",
"IfcProductDefinitionShape",
"IfcPropertyAbstraction",
"IfcRecurrencePattern",
"IfcReference",
"IfcRepresentation",
"IfcRepresentationContext",
"IfcRepresentationItem",
"IfcRepresentationMap",
"IfcPropertyDefinition", # A bit of a questionable one, and the odd one out from IfcRoot.
"IfcSchedulingTime",
"IfcShapeAspect",
"IfcTable",
"IfcTableColumn",
"IfcTableRow",
"IfcTextureCoordinateIndices",
"IfcTimePeriod",
"IfcTimeSeries",
"IfcTimeSeriesValue",
"IfcUnitAssignment",
"IfcVirtualGridIntersection",
]
total_purged = 0
while True:
total_batches = 0
print("*" * 100)
total_batch_purged = 0
for ifc_class in whitelisted_classes:
total_class_purged = 0
try:
elements = tool.Ifc.get().by_type(ifc_class)
except:
continue # Probably not in this schema?
to_purge = set()
for element in elements:
try:
if ifc_class == "IfcRepresentationItem" and element.is_a("IfcStyledItem") and element.Item:
continue
except:
to_purge.add(element.id()) # It's invalid, definitely purge it.
if tool.Ifc.get().get_total_inverses(element) == 0:
to_purge.add(element.id())
for element_id in to_purge:
try:
element = tool.Ifc.get().by_id(element_id)
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), element)
total_class_purged += 1
except:
continue
if total_class_purged > 0:
total_batch_purged += total_class_purged
print(f"Auto purged {total_class_purged} {ifc_class}")
if total_batch_purged > 0:
total_purged += total_batch_purged
print(f"Auto purged in batch: {total_batch_purged}")
total_batches += 1
if total_batch_purged == 0:
break
elif total_batches > 20:
print("Finished 20 batches. Manually stopping in case of infinite loop.")
self.report({"INFO"}, f"Auto purged {total_purged} orphaned elements")
tool.Ifc.get().write(self.filepath)
@@ -40,3 +40,14 @@ class BIMDebugProperties(PropertyGroup):
inverse_attributes: CollectionProperty(name="Inverse Attributes", type=Attribute)
inverse_references: CollectionProperty(name="Inverse References", type=Attribute)
express_file: StringProperty(name="Express File")
display_type: EnumProperty(
items=[
("BOUNDS", "Bounds", ""),
("WIRE", "Wire", ""),
("SOLID", "Solid", ""),
("TEXTURED", "Textured", ""),
],
name="Display Type",
default="BOUNDS",
)
ifc_class_purge: StringProperty(name="Unused Elements IFC Class", default="")
@@ -37,7 +37,6 @@ class BIM_PT_debug(Panel):
row = self.layout.row(align=True)
row.prop(context.scene.BIMProperties, "ifc_file", text="")
row.operator("bim.validate_ifc_file", icon="CHECKMARK", text="")
row.operator("bim.reload_selected_ifc_file", icon="FILE_REFRESH", text="")
row.operator("bim.select_ifc_file", icon="FILE_FOLDER", text="")
row = self.layout.row(align=True)
@@ -45,6 +44,9 @@ class BIM_PT_debug(Panel):
row.operator("bim.parse_express", icon="IMPORT", text="")
row.operator("bim.select_express_file", icon="FILE_FOLDER", text="")
row = layout.row()
row.operator("bim.reload_ifc_file", text="Incrementally Reload Changes")
row = layout.row()
row.operator("bim.print_ifc_file")
@@ -83,6 +85,17 @@ class BIM_PT_debug(Panel):
).percentile = context.scene.BIMDebugProperties.percentile_of_polygons
row.prop(props, "percentile_of_polygons", text="")
row = layout.split(factor=0.5, align=True)
row.prop(props, "display_type", text="")
row.operator("bim.override_display_type").display = context.scene.BIMDebugProperties.display_type
layout.operator("bim.purge_unused_representations")
row = layout.row(align=True)
row.prop(context.scene.BIMDebugProperties, "ifc_class_purge", text="")
row.operator("bim.purge_unused_elements_by_class", text="Purge Orphaned", icon="TRASH")
row.operator("bim.print_unused_elements_stats", text="", icon="INFO")
if context.active_object and context.active_object.data:
mprops = context.active_object.data.BIMMeshProperties
row = layout.row()
@@ -20,11 +20,12 @@ import bpy
from . import ui, prop, operator
classes = (
operator.SelectDiffJsonFile,
operator.VisualiseDiff,
operator.SelectDiffOldFile,
operator.SelectDiffNewFile,
operator.ExecuteIfcDiff,
operator.SelectDiffJsonFile,
operator.SelectDiffNewFile,
operator.SelectDiffObjects,
operator.SelectDiffOldFile,
operator.VisualiseDiff,
prop.Relationships,
prop.DiffProperties,
ui.BIM_PT_diff,
@@ -18,10 +18,11 @@
import bpy
import json
import ifccsv
import logging
import ifcopenshell
import blenderbim.bim.handler
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
class SelectDiffJsonFile(bpy.types.Operator):
@@ -51,8 +52,37 @@ class VisualiseDiff(bpy.types.Operator):
diff = json.load(file)
for obj in context.visible_objects:
obj.color = (1.0, 1.0, 1.0, 1.0)
element = tool.Ifc.get_entity(obj)
if not element:
if "IfcDiff Deleted Elements" in obj.users_collection[0].name:
obj.color = (1.0, 0.0, 0.0, 1.0)
continue
elif "IfcDiff Added Elements" in obj.users_collection[0].name:
obj.color = (0.0, 1.0, 0.0, 1.0)
continue
elif "IfcDiff Changed Elements" in obj.users_collection[0].name:
obj.color = (0.0, 0.0, 0.7, 1.0)
continue
if not obj.BIMObjectProperties.ifc_definition_id:
continue
ifc_file = ""
for scene in obj.users_scene:
if scene.BIMProperties.ifc_file:
ifc_file = scene.BIMProperties.ifc_file
if scene.library:
break
if ifc_file:
if ifc_file not in IfcStore.session_files:
IfcStore.session_files[ifc_file] = ifcopenshell.open(ifc_file)
element_file = IfcStore.session_files[ifc_file]
else:
element_file = ifc_file
try:
element = element_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
except:
continue
global_id = getattr(element, "GlobalId", None)
if not global_id:
@@ -115,14 +145,140 @@ class ExecuteIfcDiff(bpy.types.Operator):
def execute(self, context):
import ifcdiff
old = ifcopenshell.open(context.scene.DiffProperties.old_file)
new = ifcopenshell.open(context.scene.DiffProperties.new_file)
relationships = [r.relationship for r in context.scene.DiffProperties.diff_relationships]
query = context.scene.DiffProperties.diff_filter_elements
self.props = context.scene.DiffProperties
if tool.Ifc.get():
if self.props.active_file == "NONE":
old = ifcopenshell.open(self.props.old_file)
new = ifcopenshell.open(self.props.new_file)
elif self.props.active_file == "NEW":
old = ifcopenshell.open(self.props.old_file)
new = tool.Ifc.get()
elif self.props.active_file == "OLD":
old = tool.Ifc.get()
new = ifcopenshell.open(self.props.new_file)
else:
old = ifcopenshell.open(self.props.old_file)
new = ifcopenshell.open(self.props.new_file)
relationships = [r.relationship for r in self.props.diff_relationships]
query = self.props.diff_filter_elements
ifc_diff = ifcdiff.IfcDiff(old, new, relationships=relationships, filter_elements=query)
ifc_diff.diff()
ifc_diff.export(self.filepath)
context.scene.DiffProperties.diff_json_file = self.filepath
self.props.diff_json_file = self.filepath
self.load_changed_elements(ifc_diff)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
def load_changed_elements(self, ifc_diff):
if not tool.Ifc.get() or self.props.active_file == "NONE" or not self.props.should_load_changed_elements:
return
active_ifc = tool.Ifc.get()
logger = logging.getLogger("ImportIFC")
ifc_import_settings = blenderbim.bim.import_ifc.IfcImportSettings.factory(bpy.context, None, logger)
ifc_importer = blenderbim.bim.import_ifc.IfcImporter(ifc_import_settings)
if self.props.active_file == "NEW":
tool.Ifc.set(ifc_diff.old)
ifc_importer.file = ifc_diff.old
ifc_importer.process_context_filter()
ifc_importer.create_materials()
ifc_importer.create_styles()
elements = {ifc_diff.old.by_guid(guid) for guid in ifc_diff.deleted_elements}
ifc_importer.create_generic_elements(elements)
self.place_objs_in_collection(ifc_importer.added_data.values(), "IfcDiff Deleted Elements")
ifc_importer.added_data = {}
elements = {ifc_diff.old.by_guid(guid) for guid in ifc_diff.change_register.keys()}
ifc_importer.create_generic_elements(elements)
self.place_objs_in_collection(ifc_importer.added_data.values(), "IfcDiff Changed Elements")
elif self.props.active_file == "OLD":
tool.Ifc.set(ifc_diff.new)
ifc_importer.file = ifc_diff.new
ifc_importer.process_context_filter()
ifc_importer.create_materials()
ifc_importer.create_styles()
elements = {ifc_diff.new.by_guid(guid) for guid in ifc_diff.added_elements}
ifc_importer.create_generic_elements(elements)
self.place_objs_in_collection(ifc_importer.added_data.values(), "IfcDiff Added Elements")
ifc_importer.added_data = {}
elements = {ifc_diff.new.by_guid(guid) for guid in ifc_diff.change_register.keys()}
ifc_importer.create_generic_elements(elements)
self.place_objs_in_collection(ifc_importer.added_data.values(), "IfcDiff Changed Elements")
tool.Ifc.set(active_ifc)
def place_objs_in_collection(self, objs, name):
collection = bpy.data.collections.get(name)
if not collection:
collection = bpy.data.collections.new(name)
bpy.context.scene.collection.children.link(collection)
for obj in objs:
if isinstance(obj, bpy.types.Object):
collection.objects.link(obj)
class SelectDiffObjects(bpy.types.Operator):
bl_idname = "bim.select_diff_objects"
bl_label = "Select Diff Objects"
bl_options = {"REGISTER", "UNDO"}
mode: bpy.props.StringProperty()
def execute(self, context):
ifc_file = tool.Ifc.get()
with open(context.scene.DiffProperties.diff_json_file, "r") as file:
diff = json.load(file)
for obj in context.visible_objects:
obj.select_set(False)
if self.mode == "DELETED" and "IfcDiff Deleted Elements" in obj.users_collection[0].name:
obj.select_set(True)
continue
elif self.mode == "ADDED" and "IfcDiff Added Elements" in obj.users_collection[0].name:
obj.select_set(True)
continue
elif self.mode == "CHANGED" and "IfcDiff Changed Elements" in obj.users_collection[0].name:
obj.select_set(True)
continue
if not obj.BIMObjectProperties.ifc_definition_id:
continue
ifc_file = ""
for scene in obj.users_scene:
if scene.BIMProperties.ifc_file:
ifc_file = scene.BIMProperties.ifc_file
if scene.library:
break
if ifc_file:
if ifc_file not in IfcStore.session_files:
IfcStore.session_files[ifc_file] = ifcopenshell.open(ifc_file)
element_file = IfcStore.session_files[ifc_file]
else:
element_file = ifc_file
try:
element = element_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
except:
continue
global_id = getattr(element, "GlobalId", None)
if not global_id:
continue
if self.mode == "DELETED" and global_id in diff["deleted"]:
obj.select_set(True)
elif self.mode == "ADDED" and global_id in diff["added"]:
obj.select_set(True)
elif self.mode == "CHANGED" and global_id in diff["changed"]:
obj.select_set(True)
return {"FINISHED"}
@@ -49,3 +49,13 @@ class DiffProperties(PropertyGroup):
new_file: StringProperty(default="", name="New IFC File")
diff_relationships: CollectionProperty(type=Relationships, name="Relationships")
diff_filter_elements: StringProperty(default="", name="Filter")
should_load_changed_elements: BoolProperty(name="Load Changed Elements", default=True)
active_file: EnumProperty(
items=[
("NONE", "N/A", ""),
("OLD", "Old", ""),
("NEW", "New", ""),
],
name="Active File",
default="NEW",
)
+47 -10
View File
@@ -44,13 +44,38 @@ class BIM_PT_diff(Panel):
layout.label(text="IFC Diff Setup:")
row = layout.row(align=True)
row.prop(props, "old_file")
row.operator("bim.select_diff_old_file", icon="FILE_FOLDER", text="")
if tool.Ifc.get():
row = layout.row()
row.prop(props, "active_file")
row = layout.row(align=True)
row.prop(props, "new_file")
row.operator("bim.select_diff_new_file", icon="FILE_FOLDER", text="")
if props.active_file == "NONE":
row = layout.row(align=True)
row.prop(props, "old_file")
row.operator("bim.select_diff_old_file", icon="FILE_FOLDER", text="")
row = layout.row(align=True)
row.prop(props, "new_file")
row.operator("bim.select_diff_new_file", icon="FILE_FOLDER", text="")
elif props.active_file == "NEW":
row = layout.row(align=True)
row.prop(props, "old_file")
row.operator("bim.select_diff_old_file", icon="FILE_FOLDER", text="")
elif props.active_file == "OLD":
row = layout.row(align=True)
row.prop(props, "new_file")
row.operator("bim.select_diff_new_file", icon="FILE_FOLDER", text="")
if props.active_file != "NONE":
row = layout.row()
row.prop(props, "should_load_changed_elements")
else:
row = layout.row(align=True)
row.prop(props, "old_file")
row.operator("bim.select_diff_old_file", icon="FILE_FOLDER", text="")
row = layout.row(align=True)
row.prop(props, "new_file")
row.operator("bim.select_diff_new_file", icon="FILE_FOLDER", text="")
row = layout.row(align=True)
row.prop(props, "diff_relationships")
@@ -82,10 +107,22 @@ class BIM_PT_diff(Panel):
if DiffData.data["diff_json"]:
row = layout.row()
row.alignment = "CENTER"
row.label(text=f"{DiffData.data['total_added']} added")
row.label(text=f"{DiffData.data['total_deleted']} deleted")
row.label(text=f"{DiffData.data['total_changed']} changed")
col = row.column(align=True)
col.operator(
"bim.select_diff_objects",
icon="RESTRICT_SELECT_OFF",
text=f"Select {DiffData.data['total_added']} Added",
).mode = "ADDED"
col.operator(
"bim.select_diff_objects",
icon="RESTRICT_SELECT_OFF",
text=f"Select {DiffData.data['total_deleted']} Deleted",
).mode = "DELETED"
col.operator(
"bim.select_diff_objects",
icon="RESTRICT_SELECT_OFF",
text=f"Select {DiffData.data['total_changed']} Changed",
).mode = "CHANGED"
if DiffData.data["changes"]:
box = layout.box()
@@ -29,7 +29,7 @@ class BIM_PT_documents(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_project_setup"
bl_parent_id = "BIM_PT_tab_project_setup"
@classmethod
def poll(cls, context):
@@ -30,11 +30,13 @@ classes = (
operator.AddDrawingStyleAttribute,
operator.AddDrawingToSheet,
operator.AddReference,
operator.AddReferenceImage,
operator.AddReferenceToSheet,
operator.AddSchedule,
operator.AddScheduleToSheet,
operator.AddSheet,
operator.AddTextLiteral,
operator.AssignSelectedObjectAsProduct,
operator.BuildSchedule,
operator.CleanWireframes,
operator.ContractSheet,
@@ -50,11 +52,13 @@ classes = (
operator.DisableEditingText,
operator.DuplicateDrawing,
operator.EditAssignedProduct,
operator.EditElementFilter,
operator.EditSheet,
operator.EditText,
operator.EditTextPopup,
operator.EnableAddAnnotationType,
operator.EnableEditingAssignedProduct,
operator.EnableEditingElementFilter,
operator.EnableEditingText,
operator.ExpandSheet,
operator.ExpandTargetView,
@@ -92,10 +96,11 @@ classes = (
prop.BIMTextProperties,
prop.BIMAssignedProductProperties,
prop.BIMAnnotationProperties,
ui.BIM_PT_camera,
ui.BIM_PT_drawing_underlay,
ui.BIM_PT_sheets,
ui.BIM_PT_drawings,
ui.BIM_PT_camera,
ui.BIM_PT_element_filters,
ui.BIM_PT_drawing_underlay,
ui.BIM_PT_schedules,
ui.BIM_PT_references,
ui.BIM_PT_product_assignments,
@@ -123,6 +128,7 @@ def register():
bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties)
bpy.app.handlers.load_post.append(handler.toggleDecorationsOnLoad)
bpy.app.handlers.depsgraph_update_pre.append(handler.depsgraph_update_pre_handler)
bpy.types.VIEW3D_MT_image_add.append(ui.add_object_button)
def unregister():
@@ -136,3 +142,4 @@ def unregister():
del bpy.types.TextCurve.BIMTextProperties
bpy.app.handlers.load_post.remove(handler.toggleDecorationsOnLoad)
bpy.app.handlers.depsgraph_update_pre.remove(handler.depsgraph_update_pre_handler)
bpy.types.VIEW3D_MT_image_add.remove(ui.add_object_button)
@@ -18,6 +18,7 @@
import os
import bpy
import json
import ifcopenshell.util.element
import ifcopenshell.util.representation
import blenderbim.tool as tool
@@ -29,6 +30,7 @@ def refresh():
SheetsData.is_loaded = False
DocumentsData.is_loaded = False
DrawingsData.is_loaded = False
ElementFiltersData.is_loaded = False
AnnotationData.is_loaded = False
DecoratorData.data = {}
DecoratorData.cut_cache = {}
@@ -123,6 +125,8 @@ class DrawingsData:
[(str(s.id()), s.Name or "Unnamed", "") for s in tool.Ifc.get().by_type("IfcBuildingStorey")]
)
return results
elif bpy.context.scene.DocProperties.target_view in ["MODEL_VIEW"]:
return [(h.upper(), h, "") for h in ["Orthographic", "Perspective"]]
return [(h.upper(), h, "") for h in ["North", "South", "East", "West"]]
@classmethod
@@ -135,6 +139,55 @@ class DrawingsData:
return ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing")
class ElementFiltersData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {
"saved_searches": cls.saved_searches(),
"has_include_filter": cls.has_include_filter(),
"has_exclude_filter": cls.has_exclude_filter(),
}
cls.is_loaded = True
@classmethod
def saved_searches(cls):
if not tool.Ifc.get():
return []
groups = tool.Ifc.get().by_type("IfcGroup")
results = []
for group in groups:
try:
data = json.loads(group.Description)
if isinstance(data, dict) and data.get("type", None) == "BBIM_Search" and data.get("query", None):
results.append(group)
except:
pass
return [(str(g.id()), g.Name or "Unnamed", "") for g in sorted(results, key=lambda x: x.Name or "Unnamed")]
@classmethod
def has_include_filter(cls):
obj = bpy.context.scene.camera
if not obj:
return
element = tool.Ifc.get_entity(obj)
if not element:
return
return bool(ifcopenshell.util.element.get_pset(element, "EPset_Drawing", "Include"))
@classmethod
def has_exclude_filter(cls):
obj = bpy.context.scene.camera
if not obj:
return
element = tool.Ifc.get_entity(obj)
if not element:
return
return bool(ifcopenshell.util.element.get_pset(element, "EPset_Drawing", "Exclude"))
class DocumentsData:
data = {}
is_loaded = False
@@ -52,15 +52,20 @@ class profile_consequential:
cls.test_name = test_name
@classmethod
def log(cls):
def log(cls, args=[]):
if cls.start_time is not None:
cls.lines.append(f"{cls.test_name}\t{timer() - cls.start_time:.10f}")
args = "" if not args else "\t" + "\t".join(args)
cls.lines.append(f"{cls.test_name}\t{timer() - cls.start_time:.10f}{args}")
@classmethod
def stop(cls):
cls.log()
cls.start_time = None
print("\n".join(cls.lines))
lines = "\n".join(cls.lines)
print(lines)
import pyperclip
pyperclip.copy(lines)
cls.lines = []
@@ -156,9 +161,9 @@ class BaseDecorator:
os.path.join(bpy.context.scene.BIMProperties.data_dir, "fonts", "OpenGost Type B TT.ttf")
)
# 3D_POLYLINE_UNIFORM_COLOR is good for smoothed lines since `bgl.enable(GL_LINE_SMOOTH)` is deprecated
self.line_shader = gpu.shader.from_builtin("3D_POLYLINE_UNIFORM_COLOR")
self.base_shader = gpu.shader.from_builtin("3D_UNIFORM_COLOR")
# POLYLINE_UNIFORM_COLOR is good for smoothed lines since `bgl.enable(GL_LINE_SMOOTH)` is deprecated
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
self.base_shader = gpu.shader.from_builtin("UNIFORM_COLOR")
def get_camera_width_mm(self):
# Horrific prototype code to ensure bgl draws at drawing scales
@@ -385,8 +390,6 @@ class BaseDecorator:
# 0 is the default font, but we're fancier than that
font_id = self.font_id
dpi = context.preferences.system.dpi
color = context.preferences.addons["blenderbim"].preferences.decorations_colour
ang = -Vector((1, 0)).angle_signed(text_dir)
@@ -406,7 +409,7 @@ class BaseDecorator:
font_size_px = int(0.004118616 * mm_to_px) * font_size_mm / 2.5
pos = pos - line_no * font_size_px * rotation_matrix[1]
blf.size(font_id, font_size_px, dpi)
blf.size(font_id, font_size_px)
if box_alignment or center or vcenter:
w, h = blf.dimensions(font_id, text)
@@ -798,7 +801,7 @@ class AngleDecorator(BaseDecorator):
angle_rad = acos(cos_a)
angle = angle_rad / pi * 180
except ZeroDivisionError:
angle = 0
angle_rad, angle = 0, 0
# calculate angle position
p0, p1, p2 = [location_3d_to_region_2d(region, region3d, p) for p in vertices[i0 : i1 + 2]]
@@ -1558,15 +1561,15 @@ class CutDecorator:
gpu.state.point_size_set(1)
gpu.state.blend_set("ALPHA")
# 3D_POLYLINE_UNIFORM_COLOR is good for smoothed lines since `bgl.enable(GL_LINE_SMOOTH)` is deprecated
self.line_shader = gpu.shader.from_builtin("3D_POLYLINE_UNIFORM_COLOR")
# POLYLINE_UNIFORM_COLOR is good for smoothed lines since `bgl.enable(GL_LINE_SMOOTH)` is deprecated
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
self.line_shader.bind()
# POLYLINE_UNIFORM_COLOR specific uniforms
self.line_shader.uniform_float("viewportSize", (context.region.width, context.region.height))
self.line_shader.uniform_float("lineWidth", 2.0)
# general shader
self.shader = gpu.shader.from_builtin("3D_UNIFORM_COLOR")
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
self.shader.bind()
black = (0, 0, 0, 1)
@@ -1926,7 +1929,7 @@ class DecorationsHandler:
if cls.installed:
cls.uninstall()
handler = cls()
# NOTE: we USE POST_PIXEL here so that we can draw use both 3D_POLYLINE_UNIFORM_COLOR
# NOTE: we USE POST_PIXEL here so that we can use both POLYLINE_UNIFORM_COLOR
# and drawing text in the same handler. BUT this means that we supply coordinates in WINSPACE
cls.installed = SpaceView3D.draw_handler_add(handler, (context,), "WINDOW", "POST_PIXEL")
@@ -1944,10 +1947,12 @@ class DecorationsHandler:
self.decorators[object_type] = self.decorators["FALL"]
def get_objects_and_decorators(self, collection):
# TODO: do it in data instead of the handler for performance?
results = []
viewport = bpy.context.space_data
for obj in collection.all_objects:
if obj.hide_get():
if not obj.visible_get(viewport=viewport):
continue
element = tool.Ifc.get_entity(obj)
@@ -18,6 +18,7 @@
import bpy
import blenderbim.bim.module.drawing.decoration as decoration
import blenderbim.tool as tool
from bpy.app.handlers import persistent
@@ -37,10 +38,28 @@ def depsgraph_update_pre_handler(scene):
def set_active_camera_resolution(scene):
if not scene.camera or "/" not in scene.camera.name or not scene.DocProperties.drawings:
return
props = scene.camera.data.BIMCameraProperties
ortho_scale = max((props.width, props.height))
aspect_ratio = props.width / props.height
if (
scene.render.resolution_x != scene.camera.data.BIMCameraProperties.raster_x
or scene.render.resolution_y != scene.camera.data.BIMCameraProperties.raster_y
(scene.camera.data.ortho_scale != ortho_scale)
or (scene.render.resolution_x / scene.render.resolution_y != aspect_ratio)
):
scene.render.resolution_x = scene.camera.data.BIMCameraProperties.raster_x
scene.render.resolution_y = scene.camera.data.BIMCameraProperties.raster_y
scene.camera.data.ortho_scale = ortho_scale
diagram_scale = tool.Drawing.get_diagram_scale(scene.camera)
scale_ratio = tool.Drawing.get_scale_ratio(diagram_scale["Scale"])
if props.width > props.height:
aspect_ratio = props.height / props.width
raster_x = ortho_scale * scale_ratio * props.dpi / 0.0254
raster_y = ortho_scale * aspect_ratio * scale_ratio * props.dpi / 0.0254
else:
aspect_ratio = props.width / props.height
raster_x = ortho_scale * aspect_ratio * scale_ratio * props.dpi / 0.0254
raster_y = ortho_scale * scale_ratio * props.dpi / 0.0254
scene.render.resolution_x = scene.camera.data.BIMCameraProperties.raster_x = int(raster_x)
scene.render.resolution_y = scene.camera.data.BIMCameraProperties.raster_y = int(raster_y)
current_drawing = scene.DocProperties.drawings[scene.DocProperties.current_drawing_index]
@@ -182,8 +182,12 @@ def format_distance(
# Check values and compose string
if inches == 12:
feet += 1
inches = 0
if unit_length == "INCHES":
inches = 12
if unit_length == "FEET":
feet += 1
inches = 0
if not isArea:
add_inches = bool(inches) or not suppress_zero_inches
@@ -26,7 +26,6 @@ import shutil
import hashlib
import shapely
import subprocess
import webbrowser
import numpy as np
import multiprocessing
import ifcopenshell
@@ -42,15 +41,16 @@ import blenderbim.bim.module.drawing.annotation as annotation
import blenderbim.bim.module.drawing.sheeter as sheeter
import blenderbim.bim.module.drawing.scheduler as scheduler
import blenderbim.bim.module.drawing.helper as helper
import blenderbim.bim.export_ifc
from blenderbim.bim.module.drawing.decoration import CutDecorator
from blenderbim.bim.module.drawing.data import DecoratorData, DrawingsData
import blenderbim.bim.export_ifc
from lxml import etree
from mathutils import Vector, Color
from mathutils import Vector, Color, Matrix
from timeit import default_timer as timer
from blenderbim.bim.module.drawing.prop import RasterStyleProperty, Literal, RASTER_STYLE_PROPERTIES_EXCLUDE
from blenderbim.bim.ifc import IfcStore
from pathlib import Path
from bpy_extras.image_utils import load_image
cwd = os.path.dirname(os.path.realpath(__file__))
@@ -104,6 +104,9 @@ class AddAnnotationType(bpy.types.Operator, Operator):
)
element.ApplicableOccurrence = f"IfcAnnotation/{object_type}"
if props.create_representation_for_type and object_type == "IMAGE":
bpy.ops.bim.add_reference_image("INVOKE_DEFAULT", use_existing_object_by_name=obj.name)
class EnableAddAnnotationType(bpy.types.Operator, Operator):
bl_idname = "bim.enable_add_annotation_type"
@@ -260,7 +263,9 @@ class CreateDrawing(bpy.types.Operator):
with profile("Combine SVG layers"):
svg_path = self.combine_svgs(context, underlay_svg, linework_svg, annotation_svg)
tool.Drawing.open_with_user_command(context.preferences.addons["blenderbim"].preferences.svg_command, svg_path)
tool.Drawing.open_with_user_command(
context.preferences.addons["blenderbim"].preferences.svg_command, svg_path
)
if self.print_all:
bpy.ops.bim.activate_drawing(drawing=original_drawing_id, camera_view_point=False)
@@ -489,6 +494,11 @@ class CreateDrawing(bpy.types.Operator):
geom_settings = ifcopenshell.geom.settings(
DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True, INCLUDE_CURVES=True
)
if ifc.by_id(body_context[0]).ContextType == "Plan" and "PLAN_VIEW" in target_view:
offset = ifcopenshell.ifcopenshell_wrapper.float_array_3()
# A 2mm Z offset to combat Z-fighting in plan or RCPs
offset[2] = 0.002 if target_view == "PLAN_VIEW" else -0.002
geom_settings.offset = offset
geom_settings.set_context_ids(body_context)
it = ifcopenshell.geom.iterator(
geom_settings, ifc, multiprocessing.cpu_count(), include=elements
@@ -508,6 +518,11 @@ class CreateDrawing(bpy.types.Operator):
geom_settings = ifcopenshell.geom.settings(
DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True, INCLUDE_CURVES=True
)
if ifc.by_id(annotation_context[0]).ContextType == "Plan" and "PLAN_VIEW" in target_view:
offset = ifcopenshell.ifcopenshell_wrapper.float_array_3()
# A 2mm Z offset to combat Z-fighting in plan or RCPs
offset[2] = 0.002 if target_view == "PLAN_VIEW" else -0.002
geom_settings.offset = offset
geom_settings.set_context_ids(annotation_context)
it = ifcopenshell.geom.iterator(
geom_settings, ifc, multiprocessing.cpu_count(), include=elements
@@ -535,7 +550,7 @@ class CreateDrawing(bpy.types.Operator):
root = etree.fromstring(results)
group = root.find("{http://www.w3.org/2000/svg}g")
if not group:
if group is None:
with open(svg_path, "wb") as svg:
svg.write(etree.tostring(root))
@@ -919,7 +934,7 @@ class CreateDrawing(bpy.types.Operator):
join_criteria = join_criteria.split(",")
else:
# Drawing convention states that same objects classes with the same material are merged when cut.
join_criteria = ["class", "material.Name", 'r"Pset.*Common"."Status"']
join_criteria = ["class", "material.Name", "/Pset_.*Common/.Status", "EPset_Status.Status"]
group = root.find("{http://www.w3.org/2000/svg}g")
joined_paths = {}
@@ -951,17 +966,21 @@ class CreateDrawing(bpy.types.Operator):
# alone (e.g. dangles, cuts, invalids). See #3421.
line_strings = []
old_paths = []
has_open_paths = False
for path in el.findall("{http://www.w3.org/2000/svg}path"):
for subpath in path.attrib["d"].split("M")[1:]:
subpath = "M" + subpath.strip()
coords = [[round(float(o), 1) for o in co[1:].split(",")] for co in subpath.split()]
if coords[0] != coords[-1]:
has_open_paths = True
line_strings.append(shapely.LineString(coords))
old_paths.append(path)
unioned_line_strings = shapely.union_all(shapely.GeometryCollection(line_strings))
if hasattr(unioned_line_strings, "geoms"):
results = shapely.polygonize_full(unioned_line_strings.geoms)
else:
results = []
results = []
if has_open_paths:
unioned_line_strings = shapely.union_all(shapely.GeometryCollection(line_strings))
if hasattr(unioned_line_strings, "geoms"):
results = shapely.polygonize_full(unioned_line_strings.geoms)
# If we succeeded in generating new path geometry, remove all the
# old paths and add new ones.
@@ -1421,25 +1440,8 @@ class ActivateModel(bpy.types.Operator):
CutDecorator.uninstall()
if not bpy.app.background:
view3d_context = dict()
for window in bpy.context.window_manager.windows:
screen = window.screen
for area in screen.areas:
if area.type == "VIEW_3D":
view3d_context["window"] = window
view3d_context["screen"] = screen
view3d_context["area"] = area
for region in area.regions:
if region.type == "WINDOW":
view3d_context["region"] = region
break
break
if view3d_context:
break
if view3d_context:
bpy.ops.object.hide_view_clear(view3d_context)
with context.temp_override(**tool.Blender.get_viewport_context()):
bpy.ops.object.hide_view_clear()
bpy.ops.bim.activate_status_filters()
subcontext = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
@@ -2008,11 +2010,11 @@ class AddReferenceToSheet(bpy.types.Operator, Operator):
props = context.scene.DocProperties
active_reference = props.references[props.active_reference_index]
active_sheet = tool.Drawing.get_active_sheet(context)
reference = tool.Ifc.get().by_id(active_reference.ifc_definition_id)
extref = tool.Ifc.get().by_id(active_reference.ifc_definition_id)
if tool.Ifc.get_schema() == "IFC2X3":
reference_location = tool.Drawing.get_path_with_ext(reference.DocumentReferences[0].Location, "svg")
extref_location = tool.Drawing.get_path_with_ext(extref.DocumentReferences[0].Location, "svg")
else:
reference_location = tool.Drawing.get_path_with_ext(reference.HasDocumentReferences[0].Location, "svg")
extref_location = tool.Drawing.get_path_with_ext(extref.HasDocumentReferences[0].Location, "svg")
sheet = tool.Ifc.get().by_id(active_sheet.ifc_definition_id)
if not sheet.is_a("IfcDocumentInformation"):
@@ -2020,30 +2022,30 @@ class AddReferenceToSheet(bpy.types.Operator, Operator):
references = tool.Drawing.get_document_references(sheet)
has_reference = False
has_extref = False
for reference in references:
if reference.Location == reference_location:
has_reference = True
if reference.Location == extref_location:
has_extref = True
break
if has_reference:
if has_extref:
return
if not tool.Drawing.does_file_exist(tool.Ifc.resolve_uri(reference_location)):
self.report({"ERROR"}, f"Cannot find reference svg by path {reference_location}.")
if not tool.Drawing.does_file_exist(tool.Ifc.resolve_uri(extref_location)):
self.report({"ERROR"}, f"Cannot find reference svg by path {extref_location}.")
return
reference = tool.Ifc.run("document.add_reference", information=sheet)
id_attr = "ItemReference" if tool.Ifc.get_schema() == "IFC2X3" else "Identification"
attributes = {
id_attr: str(len([r for r in references if r.Description in ("DRAWING", "REFERENCE")]) + 1),
"Location": reference_location,
"Location": extref_location,
"Description": "REFERENCE",
}
tool.Ifc.run("document.edit_reference", reference=reference, attributes=attributes)
sheet_builder = sheeter.SheetBuilder()
sheet_builder.data_dir = context.scene.BIMProperties.data_dir
sheet_builder.add_document(reference, reference, sheet)
sheet_builder.add_document(reference, extref, sheet)
tool.Drawing.import_sheets()
@@ -2283,6 +2285,27 @@ class RemoveTextLiteral(bpy.types.Operator):
return {"FINISHED"}
class AssignSelectedObjectAsProduct(bpy.types.Operator):
bl_idname = "bim.assign_selected_as_product"
bl_label = "Assign Selected Object As Product"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
if len(context.selected_objects) != 2:
cls.poll_message_set("2 objects need to be selected")
return False
return True
def execute(self, context):
objs = context.selected_objects[:]
objs.remove(context.active_object)
other_selected_object = next(obj for obj in context.selected_objects if obj != context.active_object)
context.active_object.BIMAssignedProductProperties.relating_product = other_selected_object
bpy.ops.bim.edit_assigned_product()
return {"FINISHED"}
class EditAssignedProduct(bpy.types.Operator, Operator):
bl_idname = "bim.edit_assigned_product"
bl_label = "Edit Text Product"
@@ -2522,3 +2545,156 @@ class SelectAssignedProduct(bpy.types.Operator, Operator):
def _execute(self, context):
core.select_assigned_product(tool.Drawing, context)
class EnableEditingElementFilter(bpy.types.Operator, Operator):
bl_idname = "bim.enable_editing_element_filter"
bl_label = "Enable Editing Element Filter"
bl_options = {"REGISTER", "UNDO"}
filter_mode: bpy.props.StringProperty()
def _execute(self, context):
obj = bpy.context.scene.camera
if obj:
obj.data.BIMCameraProperties.filter_mode = self.filter_mode
class EditElementFilter(bpy.types.Operator, Operator):
bl_idname = "bim.edit_element_filter"
bl_label = "Edit Element Filter"
bl_options = {"REGISTER", "UNDO"}
filter_mode: bpy.props.StringProperty()
def _execute(self, context):
props = context.active_object.data.BIMCameraProperties
obj = bpy.context.scene.camera
element = tool.Ifc.get_entity(obj)
pset = tool.Pset.get_element_pset(element, "EPset_Drawing")
if self.filter_mode == "INCLUDE":
query = tool.Search.export_filter_query(props.include_filter_groups) or None
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Include": query})
elif self.filter_mode == "EXCLUDE":
query = tool.Search.export_filter_query(props.exclude_filter_groups) or None
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Exclude": query})
obj.data.BIMCameraProperties.filter_mode = "NONE"
bpy.ops.bim.activate_drawing(drawing=element.id(), camera_view_point=False)
class AddReferenceImage(bpy.types.Operator, Operator):
bl_idname = "bim.add_reference_image"
bl_label = "Add Reference Image"
bl_options = {"REGISTER", "UNDO"}
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True)
filepath: bpy.props.StringProperty(
name="File Path", description="Filepath used to import from", maxlen=1024, default="", subtype="FILE_PATH"
)
filter_image: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"})
filter_folder: bpy.props.BoolProperty(default=True, options={"HIDDEN", "SKIP_SAVE"})
override_existing_image: bpy.props.BoolProperty(
name="Override Existing Image",
default=True,
description=(
"Override image if it was previously loaded to Blender. If disabled, will always create a new image"
),
)
use_existing_object_by_name: bpy.props.StringProperty(
name="Use Existing Object By Name",
description="Existing object name to add a style with reference image to. If not provided will create a new object.",
options={"SKIP_SAVE"},
)
def draw(self, context):
layout = self.layout
if Path(tool.Ifc.get_path()).is_file():
layout.prop(self, "use_relative_path")
else:
self.use_relative_path = False
layout.label(text="Save the .ifc file first ")
layout.label(text="to use relative paths.")
layout.prop(self, "override_existing_image")
layout.prop(self, "use_existing_object_by_name")
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
def _execute(self, context):
abs_path = Path(self.filepath)
if self.use_relative_path:
image_filepath = abs_path.relative_to(Path(tool.Ifc.get_path()).parent)
else:
image_filepath = abs_path
ifc_file = tool.Ifc.get()
if self.override_existing_image:
params = {"check_existing": True, "force_reload": True}
else:
params = {"check_existing": False}
image = load_image(abs_path.name, abs_path.parent, **params)
def bm_add_image_plane(mesh):
bm = tool.Blender.get_bmesh_for_mesh(mesh, clean=True)
plane_scale = (Vector(image.size) / min(image.size)).to_3d()
matrix = Matrix.LocRotScale(None, None, plane_scale)
bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=1, matrix=matrix, calc_uvs=False)
tool.Blender.apply_bmesh(mesh, bm)
if self.use_existing_object_by_name:
obj = bpy.data.objects[self.use_existing_object_by_name]
bm_add_image_plane(obj.data)
bpy.ops.bim.update_representation(obj=obj.name, ifc_representation_class="")
else:
temp_mesh = bpy.data.meshes.new("temp_mesh")
bm_add_image_plane(temp_mesh)
obj = bpy.data.objects.new(image_filepath.stem, temp_mesh)
tool.Drawing.run_root_assign_class(
obj=obj,
ifc_class="IfcAnnotation",
predefined_type="IMAGE",
should_add_representation=True,
context=ifcopenshell.util.representation.get_context(ifc_file, "Model", "Body", "MODEL_VIEW"),
ifc_representation_class=None,
)
tool.Blender.remove_data_block(temp_mesh)
tool.Blender.set_active_object(obj)
material = bpy.data.materials.new(name=image_filepath.stem)
obj.data.materials.append(None) # new slot
obj.material_slots[0].material = material
bpy.ops.bim.add_style()
style = ifc_file.by_id(material.BIMMaterialProperties.ifc_style_id)
tool.Style.assign_style_to_object(style, obj)
# TODO: IfcSurfaceStyleRendering is unnecessary here, added it only because
# we don't support IfcSurfaceStyleWithTextures without Rendering yet
shading_attributes = {
"SurfaceColour": {
"Red": 1.0,
"Green": 1.0,
"Blue": 1.0,
},
"Transparency": 0.0,
"ReflectanceMethod": "NOTDEFINED",
}
ifcopenshell.api.run(
"style.add_surface_style",
tool.Ifc.get(),
style=style,
ifc_class="IfcSurfaceStyleRendering",
attributes=shading_attributes,
)
texture = ifc_file.create_entity("IfcImageTexture", Mode="DIFFUSE", URLReference=image_filepath.as_posix())
textures = [texture]
ifc_file.create_entity("IfcTextureCoordinateGenerator", Maps=textures, Mode="COORD") # UV map
tool.Ifc.run(
"style.add_surface_style",
style=style,
ifc_class="IfcSurfaceStyleWithTextures",
attributes={"Textures": textures},
)
tool.Style.reload_material_from_ifc(material)
tool.Geometry.record_object_materials(obj)
@@ -25,6 +25,7 @@ import blenderbim.tool as tool
import blenderbim.core.drawing as core
import blenderbim.bim.module.drawing.annotation as annotation
import blenderbim.bim.module.drawing.decoration as decoration
from blenderbim.bim.prop import BIMFilterGroup
from blenderbim.bim.module.drawing.data import DrawingsData, DecoratorData, SheetsData, AnnotationData
from blenderbim.bim.module.drawing.data import refresh as refresh_drawing_data
from pathlib import Path
@@ -312,7 +313,6 @@ class DocProperties(PropertyGroup):
should_use_underlay_cache: BoolProperty(name="Use Underlay Cache", default=False)
should_use_linework_cache: BoolProperty(name="Use Linework Cache", default=False)
should_use_annotation_cache: BoolProperty(name="Use Annotation Cache", default=False)
should_extract: BoolProperty(name="Should Extract", default=True)
is_editing_drawings: BoolProperty(name="Is Editing Drawings", default=False)
is_editing_schedules: BoolProperty(name="Is Editing Schedules", default=False)
is_editing_references: BoolProperty(name="Is Editing References", default=False)
@@ -375,8 +375,14 @@ class BIMCameraProperties(PropertyGroup):
custom_scale_denominator: bpy.props.StringProperty(default="100", update=update_diagram_scale)
raster_x: IntProperty(name="Raster X", default=1000)
raster_y: IntProperty(name="Raster Y", default=1000)
dpi: IntProperty(name="DPI", default=75)
width: FloatProperty(name="Width", default=50, subtype="DISTANCE")
height: FloatProperty(name="Height", default=50, subtype="DISTANCE")
is_nts: BoolProperty(name="Is NTS", update=update_is_nts)
active_drawing_style_index: IntProperty(name="Active Drawing Style Index")
filter_mode: StringProperty(name="Filter Mode", default="NONE")
include_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Include Filter")
exclude_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Exclude Filter")
# For now, this JSON dump are all the parameters that determine a camera's "Block representation"
# By checking this, you will know whether or not the camera IFC representation needs to be refreshed
@@ -509,6 +515,7 @@ ANNOTATION_TYPES_DATA = {
"REVISION_CLOUD":("Revision Cloud", "Add revision cloud", "VOLUME_DATA", "mesh"),
"FILL_AREA": ("Fill Area", "", "NODE_TEXTURE", "mesh"),
"FALL": ("Fall", "", "SORT_ASC", "curve"),
"IMAGE": ("Image", "Add reference image attached to the drawing", "TEXTURE", "mesh"),
}
# fmt: on
@@ -18,6 +18,7 @@
from blenderbim.bim.module.drawing.svgwriter import SvgWriter
import svgwrite
import openpyxl
from odf.opendocument import load as load_ods
from odf.table import Table, TableRow, TableColumn, TableCell
@@ -62,6 +63,156 @@ class Scheduler:
)
self.padding = 1
self.margin = 1
if infile.endswith("ods"):
self.schedule_ods(infile, outfile)
elif infile.endswith("xlsx"):
self.schedule_xlsx(infile, outfile)
def schedule_xlsx(self, infile, outfile):
workbook = openpyxl.open(infile, data_only=True)
sheet = workbook.active
column_dimensions = {k: v.width for k, v in sheet.column_dimensions.items()}
row_dimensions = {k: v.height for k, v in sheet.row_dimensions.items()}
default_width = 8.43 # 8.43 characters wide
default_height = 15 # 15pt seems to be the default height
merged_cells = []
for cell_range in sheet.merged_cells.ranges:
pass
y = self.margin
rows = list(sheet.iter_rows())
total_rows = len(rows)
for i, row in enumerate(rows):
# The last row may contain only null values
if i == (total_rows - 1) and not [c for c in row if c.value is not None]:
continue
x = self.margin
for cell in row:
if isinstance(cell, openpyxl.cell.cell.MergedCell):
column_letter = openpyxl.utils.get_column_letter(cell.column)
width = column_dimensions.get(column_letter, default_width)
else:
width = column_dimensions.get(cell.column_letter, default_width)
width = self.convert_character_width_to_mm(width)
height = row_dimensions.get(cell.row, default_height)
height = self.convert_to_mm(f"{height}pt")
if isinstance(cell, openpyxl.cell.cell.MergedCell):
x += width
continue
unmerged_width = width
unmerged_height = height
for cell_range in sheet.merged_cells.ranges:
if cell.coordinate not in cell_range:
continue
merged_width = 0
merged_height = 0
for merged_column in cell_range.cols:
merged_cell = sheet.cell(*merged_column[0])
column_letter = openpyxl.utils.get_column_letter(merged_cell.column)
width = column_dimensions.get(cell.column_letter, default_width)
width = self.convert_character_width_to_mm(width)
merged_width += width
for merged_row in cell_range.rows:
merged_cell = sheet.cell(*merged_row[0])
height = row_dimensions.get(merged_cell.row, default_height)
height = self.convert_to_mm(f"{height}pt")
merged_height += height
width = merged_width
height = merged_height
break
if cell.fill.patternType:
background_color = "#" + str(cell.fill.bgColor.rgb).lower()[2:]
else:
background_color = "#ffffff"
self.svg.add(
self.svg.rect(
insert=(x, y),
size=(width, height),
style=f"fill: {background_color}; stroke-width:.125; stroke: #000000;",
)
)
if not cell.value:
x += unmerged_width
continue
font_size = cell.font.size or 11 # 11pt default
font_size = font_size / FONT_SIZE_PT * FONT_SIZE # Magic?
text_position = [0.0, 0.0]
if cell.alignment.horizontal == "left":
text_position[0] = x + self.padding
horizontal_align = "left"
elif cell.alignment.horizontal == "general" and isinstance(cell.value, str):
text_position[0] = x + self.padding
horizontal_align = "left"
elif cell.alignment.horizontal in ("center", "justify", "centerContinuous", "distributed"):
text_position[0] = x + width / 2
horizontal_align = "middle"
elif cell.alignment.horizontal == "right":
text_position[0] = x + width - self.padding
horizontal_align = "right"
elif cell.alignment.horizontal == "general" and not isinstance(cell.value, str):
text_position[0] = x + width - self.padding
horizontal_align = "right"
else:
text_position[0] = x + self.padding
horizontal_align = "left"
if cell.alignment.vertical == "top":
text_position[1] = y + self.padding
vertical_align = "top"
elif cell.alignment.vertical in ("center", "justify", "distributed"):
text_position[1] = y + height / 2
vertical_align = "middle"
elif cell.alignment.vertical == "bottom":
text_position[1] = y + height - self.padding
vertical_align = "bottom"
else:
text_position[1] = y + height - self.padding
vertical_align = "bottom"
if vertical_align == "middle" and horizontal_align == "middle":
box_alignment = "center"
else:
box_alignment = f"{vertical_align}-{horizontal_align}"
if cell.font.color:
text_color = "#" + str(cell.font.color.rgb).lower()[2:]
else:
text_color = "#000000"
self.add_text(
[cell.value],
*text_position,
font_size=font_size,
box_alignment=box_alignment,
wrap_text=cell.alignment.wrapText or False,
cell_width=width,
bold=cell.font.b,
italic=cell.font.i,
text_color=text_color,
)
x += unmerged_width
y += unmerged_height
total_width = x + self.margin
total_height = y + self.margin
self.svg["width"] = "{}mm".format(total_width)
self.svg["height"] = "{}mm".format(total_height)
self.svg["viewBox"] = "0 0 {} {}".format(total_width, total_height)
self.svg.save(pretty=True)
def schedule_ods(self, infile, outfile):
doc = load_ods(infile)
# useful for debugging ods
@@ -386,6 +537,10 @@ class Scheduler:
if len(text_lines) == 1 and not wrap_text:
text_params.update(box_alignment_params)
text_tag = self.svg.text(text_lines[0], insert=(x, y), **(text_params))
if self.is_url(text_lines[0]):
anchor = self.svg.a(text_lines[0].strip())
anchor.add(text_tag)
text_tag = anchor
self.svg.add(text_tag)
return
@@ -402,14 +557,44 @@ class Scheduler:
else:
wrapped_lines = text_lines
for line_number, text_line in enumerate(wrapped_lines[::-1]):
if box_alignment.startswith("top"):
dy_dir = 1
line_number = 0
elif box_alignment.startswith("bot"):
dy_dir = -1
line_number = 0
else: # middle row
# the idea is that the middle row should always stay in the center
# e.g. dy offset for 3 lines is: 1, 0, -1
# for 2 lines: 0.5, -0.5
dy_dir = -1
line_number = (len(wrapped_lines) - 1) / 2
for text_line in wrapped_lines[::dy_dir]:
# position has to be inserted at tspan to avoid x offset between tspans
tspan = self.svg.tspan(text_line, insert=(x, y), **text_params)
# doing it here and not in tspan constructor because constructor adds unnecessary spaces
tspan.update({"dy": f"-{line_number}em"})
tspan.update({"dy": f"{line_number}em"})
if self.is_url(text_line):
anchor = self.svg.a(text_line.strip())
anchor.add(tspan)
tspan = anchor
text_tag.add(tspan)
line_number += dy_dir
self.svg.add(text_tag)
def is_url(self, value):
return value.strip().startswith("http") and " " not in value.strip() and "://" in value # Wrong but fast
def convert_character_width_to_mm(self, value):
# Excel measures widths in terms of "number of characters of the
# default font", which is most commonly 11pt Calibri. The width of the
# "0" character in Calibri is approximately 7px at 100% zoom.
px_per_character = 7
px_to_pt = 0.75
return self.convert_to_mm(f"{value * px_per_character * px_to_pt}pt")
def convert_to_mm(self, value):
# XSL is what defines the units of measurements in ODF
# https://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#datatype-positiveLength
@@ -288,9 +288,9 @@ class BaseShader:
"""
def __init__(self):
# 3D_POLYLINE_UNIFORM_COLOR is good for smoothed lines since `bgl.enable(GL_LINE_SMOOTH)` is deprecated
self.line_shader = gpu.shader.from_builtin("3D_POLYLINE_UNIFORM_COLOR")
self.base_shader = gpu.shader.from_builtin("3D_UNIFORM_COLOR")
# POLYLINE_UNIFORM_COLOR is good for smoothed lines since `bgl.enable(GL_LINE_SMOOTH)` is deprecated
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
self.base_shader = gpu.shader.from_builtin("UNIFORM_COLOR")
def get_shader(self):
"""Returns shader for this type"""
@@ -160,7 +160,8 @@ class SheetBuilder:
x = float(image.attrib["x"])
y = float(image.attrib["y"])
if image.attrib["data-type"] == "view-title":
image.attrib["x"] = str(x - readjust.x)
image.attrib["x"] = str(x + readjust.x)
# negate y offset because view-title comes AFTER foreground
image.attrib["y"] = str(y - readjust.y)
else:
image.attrib["x"] = str(x + readjust.x)
@@ -186,11 +187,11 @@ class SheetBuilder:
layout_tree.write(layout_path)
def add_document(self, reference, schedule, sheet):
view_path = tool.Drawing.get_path_with_ext(tool.Drawing.get_document_uri(schedule), "svg")
def add_document(self, reference, document, sheet):
view_path = tool.Drawing.get_path_with_ext(tool.Drawing.get_document_uri(document), "svg")
if not os.path.exists(view_path):
tool.Drawing.create_svg_schedule(schedule)
schedule_name = os.path.splitext(os.path.basename(view_path))[0]
tool.Drawing.create_svg_document(document)
document_name = os.path.splitext(os.path.basename(view_path))[0]
layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT")
layout_dir = os.path.dirname(layout_path)
@@ -206,12 +207,12 @@ class SheetBuilder:
view_height = self.convert_to_mm(view_root.attrib.get("height"))
view = ET.SubElement(layout_root, "g")
view.attrib["data-type"] = "schedule"
view.attrib["data-id"] = str(reference.id())
view.attrib["data-schedule"] = str(schedule.id())
view.attrib["data-type"] = document.Scope.lower()
view.attrib["data-document"] = str(document.id())
foreground = ET.SubElement(view, "image")
foreground.attrib["data-type"] = "table"
foreground.attrib["data-type"] = "content"
foreground.attrib["xlink:href"] = os.path.relpath(view_path, layout_dir)
foreground.attrib["x"] = str(DEFAULT_POSITION.x)
foreground.attrib["y"] = str(DEFAULT_POSITION.y)
@@ -262,7 +263,7 @@ class SheetBuilder:
self.build_titleblock(root, sheet)
self.build_drawings(root, sheet)
self.build_schedules(root, sheet)
self.build_documents(root, sheet)
with open(sheet_path, "wb") as output:
tree.write(output)
@@ -345,8 +346,12 @@ class SheetBuilder:
def build_drawings(self, root, sheet):
for view in root.findall('{http://www.w3.org/2000/svg}g[@data-type="drawing"]'):
drawing_id = int(view.attrib["data-id"])
reference = tool.Ifc.get().by_id(int(view.attrib["data-id"]))
drawing = tool.Ifc.get().by_id(view.attrib["data-drawing"])
try:
reference = tool.Ifc.get().by_id(int(view.attrib["data-id"]))
drawing = tool.Ifc.get().by_id(view.attrib["data-drawing"])
except:
# Perhaps the SVG has outdated content or is edited externally which we cannot control.
continue
images = view.findall("{http://www.w3.org/2000/svg}image")
@@ -385,10 +390,17 @@ class SheetBuilder:
for image in images:
view.remove(image)
def build_schedules(self, root, sheet):
for view in root.findall('{http://www.w3.org/2000/svg}g[@data-type="schedule"]'):
reference = tool.Ifc.get().by_id(int(view.attrib["data-id"]))
schedule = tool.Ifc.get().by_id(int(view.attrib["data-schedule"]))
def build_documents(self, root, sheet):
schedules = root.findall('{http://www.w3.org/2000/svg}g[@data-type="schedule"]')
references = root.findall('{http://www.w3.org/2000/svg}g[@data-type="reference"]')
documents = schedules + references
for view in documents:
try:
reference = tool.Ifc.get().by_id(int(view.attrib["data-id"]))
document = tool.Ifc.get().by_id(int(view.attrib["data-document"]))
except:
# Perhaps the SVG has outdated content or is edited externally which we cannot control.
continue
images = view.findall("{http://www.w3.org/2000/svg}image")
@@ -396,7 +408,7 @@ class SheetBuilder:
view_title = None
for image in images:
if image.attrib["data-type"] == "table":
if image.attrib["data-type"] == "content":
table = image
elif image.attrib["data-type"] == "view-title":
view_title = image
@@ -409,7 +421,7 @@ class SheetBuilder:
data = reference.get_info()
data.update({"Sheet" + k: v for k, v in sheet.get_info().items()})
if not data["Name"]:
data["Name"] = schedule.Name or "Unnamed"
data["Name"] = document.Name or "Unnamed"
view.append(self.parse_embedded_svg(view_title, data))
for image in images:
@@ -160,7 +160,7 @@ class SvgWriter:
def find_xml_symbol_by_id(self, id):
tree = ET.parse(self.resource_paths["Symbols"])
xml_symbol = tree.find(f'.//*[@id="{id}"]')
return External(xml_symbol) if xml_symbol else None
return External(xml_symbol) if xml_symbol is not None else None
def add_patterns(self):
path = self.resource_paths["Patterns"]
@@ -25,34 +25,35 @@ from blenderbim.bim.module.drawing.data import (
SheetsData,
DocumentsData,
DrawingsData,
ElementFiltersData,
DecoratorData,
)
from blenderbim.bim.module.drawing.prop import ANNOTATION_TYPES_DATA
class BIM_PT_camera(Panel):
bl_label = "Drawing Generation"
bl_label = "Active Drawing"
bl_idname = "BIM_PT_camera"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "data"
@classmethod
def poll(cls, context):
return context.camera and hasattr(context.active_object.data, "BIMCameraProperties")
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_drawings"
def draw(self, context):
layout = self.layout
if "/" not in context.active_object.name:
layout.label(text="This is not a BIM camera.")
if not (context.scene.camera and hasattr(context.scene.camera.data, "BIMCameraProperties")):
row = self.layout.row()
row.label(text="No Active Drawing", icon="ERROR")
return
layout.use_property_split = True
dprops = context.scene.DocProperties
props = context.active_object.data.BIMCameraProperties
if "/" not in context.scene.camera.name:
self.layout.label(text="This is not a BIM camera.")
return
col = layout.column(align=True)
self.layout.use_property_split = True
dprops = context.scene.DocProperties
props = context.scene.camera.data.BIMCameraProperties
col = self.layout.column(align=True)
row = col.row(align=True)
row.prop(props, "has_underlay", icon="OUTLINER_OB_IMAGE")
row.prop(dprops, "should_use_underlay_cache", text="", icon="FILE_REFRESH")
@@ -63,32 +64,90 @@ class BIM_PT_camera(Panel):
row.prop(props, "has_annotation", icon="MOD_EDGESPLIT")
row.prop(dprops, "should_use_annotation_cache", text="", icon="FILE_REFRESH")
row = layout.row()
row = self.layout.row()
row.prop(props, "calculate_shapely_surfaces")
row = layout.row()
row = self.layout.row()
row.prop(props, "calculate_svgfill_surfaces")
row = layout.row()
row.prop(dprops, "should_extract")
row = self.layout.row()
row.prop(props, "width")
row = self.layout.row()
row.prop(props, "height")
row = layout.row()
row.prop(props, "raster_x")
row = layout.row()
row.prop(props, "raster_y")
row = self.layout.row()
row.prop(context.scene.camera.data, "clip_end", text="Depth")
row = layout.row(align=True)
row.prop(props, "diagram_scale")
row = self.layout.row(align=True)
row.prop(props, "diagram_scale", text="Scale")
row.prop(props, "is_nts", text="", icon="MOD_EDGESPLIT")
if props.diagram_scale == "CUSTOM":
row = layout.row(align=True)
row = self.layout.row(align=True)
row.prop(props, "custom_scale_numerator", text="Custom Scale")
row.prop(props, "custom_scale_denominator", text="")
row = layout.row(align=True)
if props.has_underlay:
row = self.layout.row()
row.prop(props, "dpi")
row = self.layout.row(align=True)
row.operator("bim.create_drawing", text="Create Drawing", icon="OUTPUT")
op = row.operator("bim.open_drawing", icon="URL", text="")
op.view = context.active_object.name.split("/")[1]
op.view = context.scene.camera.name.split("/")[1]
class BIM_PT_element_filters(Panel):
bl_label = "Element Filters"
bl_idname = "BIM_PT_element_filters"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_camera"
@classmethod
def poll(cls, context):
return (
context.scene.camera
and context.active_object
and hasattr(context.active_object.data, "BIMCameraProperties")
)
def draw(self, context):
if not ElementFiltersData.is_loaded:
ElementFiltersData.load()
props = context.scene.camera.data.BIMCameraProperties
if props.filter_mode == "INCLUDE":
blenderbim.bim.helper.draw_filter(
self.layout, props.include_filter_groups, ElementFiltersData, "drawing_include"
)
row = self.layout.row(align=True)
row.operator(
"bim.edit_element_filter", icon="CHECKMARK", text="Save Include Filter"
).filter_mode = "INCLUDE"
row.operator("bim.enable_editing_element_filter", icon="CANCEL", text="").filter_mode = "NONE"
elif props.filter_mode == "EXCLUDE":
blenderbim.bim.helper.draw_filter(
self.layout, props.exclude_filter_groups, ElementFiltersData, "drawing_exclude"
)
row = self.layout.row(align=True)
row.operator(
"bim.edit_element_filter", icon="CHECKMARK", text="Save Exclude Filter"
).filter_mode = "EXCLUDE"
row.operator("bim.enable_editing_element_filter", icon="CANCEL", text="").filter_mode = "NONE"
else:
row = self.layout.row(align=True)
text = "Include Filter" if ElementFiltersData.data["has_include_filter"] else "No Include Filter Found"
icon = "GREASEPENCIL" if ElementFiltersData.data["has_include_filter"] else "ADD"
row.label(text=text, icon="FILTER")
row.operator("bim.enable_editing_element_filter", icon=icon, text="").filter_mode = "INCLUDE"
row = self.layout.row(align=True)
text = "Exclude Filter" if ElementFiltersData.data["has_exclude_filter"] else "No Exclude Filter Found"
icon = "GREASEPENCIL" if ElementFiltersData.data["has_exclude_filter"] else "ADD"
row.label(text=text, icon="FILTER")
row.operator("bim.enable_editing_element_filter", icon=icon, text="").filter_mode = "EXCLUDE"
class BIM_PT_drawing_underlay(Panel):
@@ -97,12 +156,16 @@ class BIM_PT_drawing_underlay(Panel):
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "data"
bl_context = "scene"
bl_parent_id = "BIM_PT_camera"
@classmethod
def poll(cls, context):
return context.camera and hasattr(context.active_object.data, "BIMCameraProperties")
return (
context.scene.camera
and context.active_object
and hasattr(context.active_object.data, "BIMCameraProperties")
)
def draw(self, context):
layout = self.layout
@@ -164,10 +227,8 @@ class BIM_PT_drawings(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "DRAWINGS") and tool.Ifc.get()
bl_parent_id = "BIM_PT_tab_drawings"
bl_options = {"HIDE_HEADER"}
def draw(self, context):
if not DrawingsData.is_loaded:
@@ -245,10 +306,8 @@ class BIM_PT_schedules(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "DRAWINGS") and tool.Ifc.get()
bl_parent_id = "BIM_PT_tab_schedules"
bl_options = {"HIDE_HEADER"}
def draw(self, context):
if not DocumentsData.is_loaded:
@@ -297,10 +356,8 @@ class BIM_PT_references(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "DRAWINGS") and tool.Ifc.get()
bl_parent_id = "BIM_PT_tab_references"
bl_options = {"HIDE_HEADER"}
def draw(self, context):
if not DocumentsData.is_loaded:
@@ -341,10 +398,8 @@ class BIM_PT_sheets(Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return tool.Blender.is_tab(context, "DRAWINGS") and tool.Ifc.get()
bl_parent_id = "BIM_PT_tab_sheets"
bl_options = {"HIDE_HEADER"}
def draw(self, context):
if not SheetsData.is_loaded:
@@ -413,13 +468,16 @@ class BIM_PT_product_assignments(Panel):
if props.is_editing_product:
row = self.layout.row(align=True)
row.prop(props, "relating_product", text="")
row.operator("bim.assign_selected_as_product", icon="OBJECT_DATA", text="")
row.operator("bim.edit_assigned_product", icon="CHECKMARK", text="")
row.operator("bim.disable_editing_assigned_product", icon="CANCEL", text="")
else:
row = self.layout.row(align=True)
row.label(text=ProductAssignmentsData.data["relating_product"] or "No Relating Product", icon="OBJECT_DATA")
row.operator("bim.enable_editing_assigned_product", icon="GREASEPENCIL", text="")
row.operator("bim.select_assigned_product", icon="RESTRICT_SELECT_OFF", text="")
col = row.column()
col.operator("bim.select_assigned_product", icon="RESTRICT_SELECT_OFF", text="")
col.enabled = bool(ProductAssignmentsData.data["relating_product"])
class BIM_PT_text(Panel):
@@ -601,3 +659,7 @@ class BIM_UL_sheets(bpy.types.UIList):
if not flt_flags:
return flt_flags, flt_neworder
return flt_flags, flt_neworder
def add_object_button(self, context):
self.layout.operator("bim.add_reference_image", icon="TEXTURE", text="IFC Reference Image")
@@ -186,6 +186,9 @@ def create_annotation_occurrence(context):
tool.Collector.assign(obj)
tool.Blender.select_and_activate_single_object(context, obj)
if relating_type_repr is None and props.object_type == "IMAGE":
bpy.ops.bim.add_reference_image("INVOKE_DEFAULT", use_existing_object_by_name=obj.name)
def create_annotation():
props = bpy.context.scene.BIMAnnotationProperties
@@ -194,6 +197,10 @@ def create_annotation():
else:
object_type = props.object_type
bpy.ops.bim.add_annotation(object_type=object_type, data_type=ANNOTATION_TYPES_DATA[object_type][-1])
if props.object_type == "IMAGE":
bpy.ops.bim.add_reference_image(
"INVOKE_DEFAULT", use_existing_object_by_name=bpy.context.active_object.name
)
class AnnotationToolUI:
@@ -1,5 +1,5 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
@@ -20,17 +20,18 @@ import bpy
from . import ui, prop, operator
classes = (
operator.SelectCobieIfcFile,
operator.SelectCobieJsonFile,
operator.ExecuteIfcCobie,
prop.COBieProperties,
ui.BIM_PT_cobie,
operator.ExecuteIfcFM,
operator.ExecuteIfcFMFederate,
operator.SelectFMIfcFile,
operator.SelectFMSpreadsheetFiles,
prop.BIMFMProperties,
ui.BIM_PT_fm,
)
def register():
bpy.types.Scene.COBieProperties = bpy.props.PointerProperty(type=prop.COBieProperties)
bpy.types.Scene.BIMFMProperties = bpy.props.PointerProperty(type=prop.BIMFMProperties)
def unregister():
del bpy.types.Scene.COBieProperties
del bpy.types.Scene.BIMFMProperties
@@ -1,5 +1,5 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
@@ -16,34 +16,33 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import olca
import blenderbim.tool as tool
import os
import ifcfm
import importlib
def refresh():
LcaData.is_loaded = False
FMData.is_loaded = False
class LcaData:
class FMData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {
"product_systems": cls.product_systems(),
}
cls.is_loaded = True
cls.data = {}
cls.data["engine"] = cls.engine()
@classmethod
def product_systems(cls):
if not bpy.context.scene.BIMLCAProperties.is_connected:
return []
def engine(cls):
results = []
client = olca.Client(context.preferences.addons["blenderbim"].preferences.openlca_port)
try:
results = [(ps.name, ps.name, "") for ps in client.get_all(olca.ProductSystem)]
except:
pass
fm_dir = os.path.dirname(ifcfm.__file__)
for f in os.listdir(fm_dir):
if f.endswith(".py") and not f.startswith("_"):
preset = os.path.splitext(f)[0]
module = importlib.import_module(f"ifcfm.{preset}")
config = getattr(module, "config")
results.append((preset, config["name"], config["description"]))
return results
@@ -0,0 +1,157 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import os
import bpy
import json
import ifcfm
import logging
import tempfile
import ifcopenshell
import blenderbim.tool as tool
class SelectFMIfcFile(bpy.types.Operator):
bl_idname = "bim.select_fm_ifc_file"
bl_label = "Select FM IFC File"
bl_options = {"REGISTER", "UNDO"}
filename_ext = ".ifc"
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
files: bpy.props.CollectionProperty(name="File Path", type=bpy.types.OperatorFileListElement)
def execute(self, context):
props = context.scene.BIMFMProperties
props.ifc_files.clear()
dirname = os.path.dirname(self.filepath)
for f in self.files:
new = props.ifc_files.add()
new.name = os.path.join(dirname, f.name)
props.ifc_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcFM(bpy.types.Operator):
bl_idname = "bim.execute_ifcfm"
bl_label = "Execute IfcFM"
file_format: bpy.props.StringProperty()
filter_glob: bpy.props.StringProperty(default="*.csv;*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
@classmethod
def poll(cls, context):
props = context.scene.BIMFMProperties
return props.should_load_from_memory or props.ifc_file
def invoke(self, context, event):
props = context.scene.BIMFMProperties
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context):
props = context.scene.BIMFMProperties
ifc_file = tool.Ifc.get()
filepaths = []
if not (ifc_file and props.should_load_from_memory):
if len(props.ifc_files):
ifc_files = [ifcopenshell.open(f.name) for f in props.ifc_files]
filepaths = [f.name for f in props.ifc_files]
else:
ifc_files = [ifcopenshell.open(props.ifc_file)]
else:
ifc_files = [ifc_file]
for i, ifc_file in enumerate(ifc_files):
if filepaths:
dirname = os.path.dirname(self.filepath)
prefix, _ = os.path.splitext(os.path.basename(filepaths[i]))
basename = os.path.basename(self.filepath)
filepath = os.path.join(dirname, f"{prefix}-{basename}")
else:
filepath = self.filepath
parser = ifcfm.Parser(preset=props.engine)
parser.parse(ifc_file)
writer = ifcfm.Writer(parser)
writer.write()
if props.format == "csv":
writer.write_csv("tmp/")
elif props.format == "ods":
writer.write_ods(filepath)
elif props.format == "xlsx":
writer.write_xlsx(filepath)
return {"FINISHED"}
class SelectFMSpreadsheetFiles(bpy.types.Operator):
bl_idname = "bim.select_fm_spreadsheet_files"
bl_label = "Select FM Spreadsheet Files"
bl_options = {"REGISTER", "UNDO"}
filter_glob: bpy.props.StringProperty(default="*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
files: bpy.props.CollectionProperty(name="File Path", type=bpy.types.OperatorFileListElement)
def execute(self, context):
props = context.scene.BIMFMProperties
props.spreadsheet_files.clear()
dirname = os.path.dirname(self.filepath)
for f in self.files:
new = props.spreadsheet_files.add()
new.name = os.path.join(dirname, f.name)
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcFMFederate(bpy.types.Operator):
bl_idname = "bim.execute_ifcfm_federate"
bl_label = "Execute IfcFM"
file_format: bpy.props.StringProperty()
filter_glob: bpy.props.StringProperty(default="*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
@classmethod
def poll(cls, context):
props = context.scene.BIMFMProperties
return props.spreadsheet_files
def invoke(self, context, event):
props = context.scene.BIMFMProperties
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
def execute(self, context):
props = context.scene.BIMFMProperties
parser = ifcfm.Parser(preset=props.engine)
parser.federate([f.name for f in props.spreadsheet_files])
writer = ifcfm.Writer(parser)
writer.write()
if props.format == "ods":
writer.write_ods(self.filepath)
elif props.format == "xlsx":
writer.write_xlsx(self.filepath)
return {"FINISHED"}
@@ -1,5 +1,5 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
@@ -17,6 +17,8 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
from blenderbim.bim.module.fm.data import FMData
from blenderbim.bim.prop import StrProperty
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
@@ -30,9 +32,24 @@ from bpy.props import (
)
class COBieProperties(PropertyGroup):
cobie_ifc_file: StringProperty(default="", name="COBie IFC File")
cobie_types: StringProperty(default=".COBieType", name="COBie Types")
cobie_components: StringProperty(default=".COBie", name="COBie Components")
cobie_json_file: StringProperty(default="", name="COBie JSON File")
def get_engine(self, context):
if not FMData.is_loaded:
FMData.load()
return FMData.data["engine"]
class BIMFMProperties(PropertyGroup):
ifc_file: StringProperty(default="", name="IFC File")
ifc_files: CollectionProperty(name="IFC Files", type=StrProperty)
spreadsheet_files: CollectionProperty(name="Spreadsheets", type=StrProperty)
should_load_from_memory: BoolProperty(default=False, name="Load from Memory")
engine: EnumProperty(items=get_engine, name="Engine")
format: EnumProperty(
items=[
("csv", "csv", ""),
("xlsx", "xlsx", ""),
("ods", "ods", ""),
],
name="Format",
default="ods",
)
@@ -1,5 +1,5 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
@@ -19,22 +19,26 @@
import blenderbim.tool as tool
from bpy.types import Panel
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.fm.data import FMData
class BIM_PT_cobie(Panel):
bl_label = "COBie"
bl_idname = "BIM_PT_cobie"
class BIM_PT_fm(Panel):
bl_label = "Facility Management"
bl_idname = "BIM_PT_fm"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_handover"
def draw(self, context):
if not FMData.is_loaded:
FMData.load()
layout = self.layout
layout.use_property_split = True
scene = context.scene
props = scene.COBieProperties
props = scene.BIMFMProperties
if IfcStore.get_file():
row = layout.row()
@@ -42,22 +46,23 @@ class BIM_PT_cobie(Panel):
if not IfcStore.get_file() or not props.should_load_from_memory:
row = layout.row(align=True)
row.prop(props, "cobie_ifc_file")
row.operator("bim.select_cobie_ifc_file", icon="FILE_FOLDER", text="")
if len(props.ifc_files) > 1:
row.label(text=f"{len(props.ifc_files)} Files Selected")
else:
row.prop(props, "ifc_file")
row.operator("bim.select_fm_ifc_file", icon="FILE_FOLDER", text="")
row = layout.row()
row.prop(props, "cobie_types")
row.prop(props, "engine")
row = layout.row()
row.prop(props, "cobie_components")
row.prop(props, "format")
row = layout.row()
op = row.operator("bim.execute_ifcfm", text="Convert To Spreadsheet")
row = layout.row(align=True)
row.prop(props, "cobie_json_file")
row.operator("bim.select_cobie_json_file", icon="FILE_FOLDER", text="")
row.label(text=f"{len(props.spreadsheet_files)} Spreadsheets Selected")
row.operator("bim.select_fm_spreadsheet_files", icon="FILE_FOLDER", text="")
row = layout.row()
op = row.operator("bim.execute_ifc_cobie", text="CSV")
op.file_format = "csv"
op = row.operator("bim.execute_ifc_cobie", text="ODS")
op.file_format = "ods"
op = row.operator("bim.execute_ifc_cobie", text="XLSX")
op.file_format = "xlsx"
op = row.operator("bim.execute_ifcfm_federate", text="Merge Spreadsheets")
@@ -22,37 +22,57 @@ from . import ui, prop, operator
classes = (
operator.AddRepresentation,
operator.CopyRepresentation,
operator.DisableEditingRepresentationItems,
operator.EditObjectPlacement,
operator.EnableEditingRepresentationItems,
operator.FlipObject,
operator.GetRepresentationIfcParameters,
operator.DuplicateMoveLinkedAggregate,
operator.DuplicateMoveLinkedAggregateMacro,
operator.OverrideDelete,
operator.OverrideDuplicateMove,
operator.OverrideDuplicateMoveAggregate,
operator.OverrideDuplicateMoveAggregateMacro,
operator.OverrideDuplicateMoveLinked,
operator.OverrideDuplicateMoveLinkedMacro,
operator.OverrideDuplicateMoveMacro,
operator.OverrideJoin,
operator.OverrideMeshSeparate,
operator.OverrideModeSetEdit,
operator.OverrideModeSetObject,
operator.OverrideOriginSet,
operator.OverrideOutlinerDelete,
operator.OverridePasteBuffer,
operator.PurgeUnusedRepresentations,
operator.RefreshAggregate,
operator.RefreshLinkedAggregate,
operator.RemoveConnection,
operator.RemoveRepresentation,
operator.SelectConnection,
operator.SwitchRepresentation,
operator.UpdateParametricRepresentation,
operator.UpdateRepresentation,
operator.RemoveRepresentationItem,
operator.EnableEditingRepresentationItemStyle,
operator.EditRepresentationItemStyle,
operator.DisableEditingRepresentationItemStyle,
operator.UnassignRepresentationItemStyle,
operator.EnableEditingRepresentationItemShapeAspect,
operator.EditRepresentationItemShapeAspect,
operator.DisableEditingRepresentationItemShapeAspect,
operator.RemoveRepresentationItemFromShapeAspect,
prop.RepresentationItem,
prop.ShapeAspect,
prop.BIMObjectGeometryProperties,
prop.BIMGeometryProperties,
ui.BIM_PT_derived_placements,
ui.BIM_PT_placement,
ui.BIM_PT_representations,
ui.BIM_PT_representation_items,
ui.BIM_PT_connections,
ui.BIM_PT_mesh,
ui.BIM_PT_derived_coordinates,
ui.BIM_PT_workarounds,
ui.BIM_MT_object_set_origin,
ui.BIM_MT_separate,
ui.BIM_MT_hotkey_separate,
ui.BIM_UL_representation_items,
)
@@ -64,15 +84,16 @@ def register():
operator.OverrideDuplicateMoveMacro.define("TRANSFORM_OT_translate")
operator.OverrideDuplicateMoveLinkedMacro.define("BIM_OT_override_object_duplicate_move_linked")
operator.OverrideDuplicateMoveLinkedMacro.define("TRANSFORM_OT_translate")
operator.OverrideDuplicateMoveAggregateMacro.define("BIM_OT_override_object_duplicate_move_aggregate")
operator.OverrideDuplicateMoveAggregateMacro.define("TRANSFORM_OT_translate")
operator.DuplicateMoveLinkedAggregateMacro.define("BIM_OT_object_duplicate_move_linked_aggregate")
operator.DuplicateMoveLinkedAggregateMacro.define("TRANSFORM_OT_translate")
bpy.types.Object.BIMGeometryProperties = bpy.props.PointerProperty(type=prop.BIMObjectGeometryProperties)
bpy.types.Scene.BIMGeometryProperties = bpy.props.PointerProperty(type=prop.BIMGeometryProperties)
bpy.types.OBJECT_PT_transform.append(ui.BIM_PT_transform)
bpy.types.VIEW3D_MT_object.append(ui.object_menu)
bpy.types.OUTLINER_MT_object.append(ui.outliner_menu)
bpy.types.VIEW3D_MT_object_context_menu.append(ui.object_menu)
bpy.types.VIEW3D_MT_edit_mesh.append(ui.edit_mesh_menu)
bpy.types.VIEW3D_HT_header.append(ui.mode_menu)
wm = bpy.context.window_manager
if wm.keyconfigs.addon:
km = wm.keyconfigs.addon.keymaps.new(name="Object Mode", space_type="EMPTY")
@@ -82,7 +103,9 @@ def register():
addon_keymaps.append((km, kmi))
kmi = km.keymap_items.new("bim.override_object_duplicate_move_linked_macro", "D", "PRESS", alt=True)
addon_keymaps.append((km, kmi))
kmi = km.keymap_items.new("bim.override_object_duplicate_move_aggregate_macro", "D", "PRESS", ctrl=True, shift=True)
kmi = km.keymap_items.new(
"bim.object_duplicate_move_linked_aggregate_macro", "D", "PRESS", ctrl=True, shift=True
)
addon_keymaps.append((km, kmi))
kmi = km.keymap_items.new("bim.override_paste_buffer", "V", "PRESS", ctrl=True)
addon_keymaps.append((km, kmi))
@@ -97,6 +120,9 @@ def register():
km = wm.keyconfigs.addon.keymaps.new(name="Mesh", space_type="EMPTY")
kmi = km.keymap_items.new("bim.override_mode_set_object", "TAB", "PRESS")
addon_keymaps.append((km, kmi))
kmi = km.keymap_items.new("wm.call_menu", "P", "PRESS")
kmi.properties.name = ui.BIM_MT_hotkey_separate.bl_idname
addon_keymaps.append((km, kmi))
km = wm.keyconfigs.addon.keymaps.new(name="Curve", space_type="EMPTY")
kmi = km.keymap_items.new("bim.override_mode_set_object", "TAB", "PRESS")
@@ -113,9 +139,10 @@ def register():
def unregister():
bpy.types.VIEW3D_MT_object.remove(ui.object_menu)
bpy.types.OBJECT_PT_transform.remove(ui.BIM_PT_transform)
bpy.types.OUTLINER_MT_object.remove(ui.outliner_menu)
bpy.types.VIEW3D_MT_object_context_menu.remove(ui.outliner_menu)
bpy.types.VIEW3D_MT_edit_mesh.remove(ui.edit_mesh_menu)
bpy.types.VIEW3D_HT_header.remove(ui.mode_menu)
del bpy.types.Scene.BIMGeometryProperties
del bpy.types.Object.BIMGeometryProperties
wm = bpy.context.window_manager

Some files were not shown because too many files have changed in this diff Show More