From 5c73ef0a6d1527feb5493603d9d30f1ff03fd00f Mon Sep 17 00:00:00 2001 From: Gorgious56 Date: Fri, 25 Aug 2023 15:13:07 +0200 Subject: [PATCH 01/81] Fix #3641 : Error when creating roof type --- src/blenderbim/blenderbim/bim/module/type/operator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/bim/module/type/operator.py b/src/blenderbim/blenderbim/bim/module/type/operator.py index ea07090640..ebb624829d 100644 --- a/src/blenderbim/blenderbim/bim/module/type/operator.py +++ b/src/blenderbim/blenderbim/bim/module/type/operator.py @@ -445,7 +445,7 @@ class AddType(bpy.types.Operator, tool.Ifc.Operator): should_add_representation=True, context=body, ) - tool.Blender.select_and_activate_single_object(obj) + tool.Blender.select_and_activate_single_object(context, obj) bpy.ops.bim.add_roof() bpy.ops.bim.load_type_thumbnails(ifc_class=ifc_class) From e9c24a265635a03ee0f41d0aa2d42eca4ca56b4e Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 26 Aug 2023 15:15:19 +1000 Subject: [PATCH 02/81] Fix #3587. IfcCSV now supports custom formatting functions. --- .../blenderbim/bim/module/csv/operator.py | 15 ++- .../blenderbim/bim/module/csv/prop.py | 2 + .../blenderbim/bim/module/csv/ui.py | 5 +- src/ifccsv/ifccsv.py | 27 ++++- .../ifcopenshell/util/selector.py | 101 ++++++++++++++++++ .../ifcopenshell/util/unit.py | 1 + .../test/util/test_selector.py | 26 +++++ 7 files changed, 174 insertions(+), 3 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/csv/operator.py b/src/blenderbim/blenderbim/bim/module/csv/operator.py index c1b63e4dd3..daa85fbab9 100644 --- a/src/blenderbim/blenderbim/bim/module/csv/operator.py +++ b/src/blenderbim/blenderbim/bim/module/csv/operator.py @@ -101,6 +101,7 @@ class ImportCsvAttributes(bpy.types.Operator): new.sort = attribute["sort"] new.group = attribute["group"] new.summary = attribute["summary"] + new.formatting = attribute["formatting"] return {"FINISHED"} def invoke(self, context, event): @@ -123,7 +124,14 @@ class ExportCsvAttributes(bpy.types.Operator): data = { "query": tool.Search.export_filter_query(props.filter_groups), "attributes": [ - {"name": a.name, "header": a.header, "sort": a.sort, "group": a.group, "summary": a.summary} + { + "name": a.name, + "header": a.header, + "sort": a.sort, + "group": a.group, + "summary": a.summary, + "formatting": a.formatting, + } for a in props.csv_attributes ], } @@ -173,6 +181,7 @@ class ExportIfcCsv(bpy.types.Operator): sort = [] groups = [] summaries = [] + formatting = [] for attribute in props.csv_attributes: if attribute.sort != "NONE": sort.append({"name": attribute.name, "order": attribute.sort}) @@ -181,6 +190,9 @@ class ExportIfcCsv(bpy.types.Operator): if attribute.summary != "NONE": summaries.append({"name": attribute.name, "type": attribute.summary}) + if attribute.formatting != "{{value}}" and "{{value}}" in attribute.formatting: + formatting.append({"name": attribute.name, "format": attribute.formatting}) + sep = props.csv_custom_delimiter if props.csv_delimiter == "CUSTOM" else props.csv_delimiter ifc_csv.export( ifc_file, @@ -198,6 +210,7 @@ class ExportIfcCsv(bpy.types.Operator): sort=sort, groups=groups, summaries=summaries, + formatting=formatting, ) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/csv/prop.py b/src/blenderbim/blenderbim/bim/module/csv/prop.py index 31a334e389..db1ae07071 100644 --- a/src/blenderbim/blenderbim/bim/module/csv/prop.py +++ b/src/blenderbim/blenderbim/bim/module/csv/prop.py @@ -58,6 +58,7 @@ class CsvAttribute(PropertyGroup): ("MAX", "Max", "Gets the maximum value of all rows"), ] ) + formatting: StringProperty(default="{{value}}", name="Formatting") class CsvProperties(PropertyGroup): @@ -94,4 +95,5 @@ class CsvProperties(PropertyGroup): should_show_sort: BoolProperty(default=False, name="Show Sorting") should_show_group: BoolProperty(default=False, name="Show Grouping") should_show_summary: BoolProperty(default=False, name="Show Summary") + should_show_formatting: BoolProperty(default=False, name="Show Formatting") should_load_from_memory: BoolProperty(default=False, name="Load from Memory") diff --git a/src/blenderbim/blenderbim/bim/module/csv/ui.py b/src/blenderbim/blenderbim/bim/module/csv/ui.py index c1e5c93222..425bb2cb8d 100644 --- a/src/blenderbim/blenderbim/bim/module/csv/ui.py +++ b/src/blenderbim/blenderbim/bim/module/csv/ui.py @@ -23,7 +23,7 @@ from blenderbim.bim.module.search.data import SearchData class BIM_PT_ifccsv(Panel): - bl_label = "CSV Import/Export" + bl_label = "Spreadsheet Import/Export" bl_idname = "BIM_PT_ifccsv" bl_options = {"DEFAULT_CLOSED"} bl_space_type = "PROPERTIES" @@ -86,6 +86,7 @@ class BIM_PT_ifccsv(Panel): row.prop(props, "should_show_sort", icon="SORTSIZE", text="") row.prop(props, "should_show_group", icon="OUTLINER_COLLECTION", text="") row.prop(props, "should_show_summary", icon="SYNTAX_ON", text="") + row.prop(props, "should_show_formatting", icon="CON_TRANSLIKE", text="") total = len(props.csv_attributes) for index, attribute in enumerate(props.csv_attributes): @@ -100,6 +101,8 @@ class BIM_PT_ifccsv(Panel): row.prop(attribute, "varies_value", text="") if props.should_show_summary: row.prop(attribute, "summary", text="") + if props.should_show_formatting: + row.prop(attribute, "formatting", text="") if total > 1: if index != 0: op = row.operator(f"bim.reorder_csv_attribute", icon="TRIA_UP", text="") diff --git a/src/ifccsv/ifccsv.py b/src/ifccsv/ifccsv.py index 621f2d6595..ae5c03ef47 100755 --- a/src/ifccsv/ifccsv.py +++ b/src/ifccsv/ifccsv.py @@ -75,6 +75,7 @@ class IfcCsv: sort=None, groups=None, summaries=None, + formatting=None, ): self.ifc_file = ifc_file self.results = [] @@ -116,6 +117,7 @@ class IfcCsv: self.group_results(groups, attributes) self.summarise_results(summaries, attributes) self.sort_results(sort, attributes, include_global_id) + self.format_results(formatting, attributes, null) if format == "csv": self.export_csv(output, delimiter=delimiter) @@ -225,7 +227,27 @@ class IfcCsv: self.summaries[si] = max(summary_values[si]) self.summaries[si] = summary_type.title() + ": " + str(self.summaries[si]) + def format_results(self, formatting, attributes, null): + if not formatting: + return + + formatting_indices = {} + + for data in formatting: + index = attributes.index(data["name"]) + formatting_indices[index] = data["format"] + + for row in self.results: + for index, format_query in formatting_indices.items(): + if row[index] == null: + continue + if not isinstance(row[index], str): + row[index] = '"' + str(row[index]) + '"' + row[index] = ifcopenshell.util.selector.format(format_query.replace("{{value}}", row[index])) + def sort_results(self, sort, attributes, include_global_id): + if not self.results: + return if sort: def natural_sort(value): if isinstance(value, str): @@ -240,7 +262,10 @@ class IfcCsv: reverse = sort_data["order"] == "DESC" self.results = sorted(self.results, key=lambda x: natural_sort(x[i]), reverse=reverse) else: - self.results = sorted(self.results, key=lambda x: x[1 if include_global_id else 0]) + if include_global_id and len(self.results[0]) > 1: + self.results = sorted(self.results, key=lambda x: x[1]) + elif not include_global_id: + self.results = sorted(self.results, key=lambda x: x[0]) def export_csv(self, output, delimiter=None): with open(output, "w", newline="", encoding="utf-8") as f: diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index 097ea409ff..0acd0aa44e 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -20,6 +20,7 @@ import re import lark import ifcopenshell.util import ifcopenshell.util.fm +import ifcopenshell.util.unit import ifcopenshell.util.element import ifcopenshell.util.classification @@ -112,6 +113,106 @@ get_element_grammar = lark.Lark( """ ) +format_grammar = lark.Lark( + """start: function + + function: round | format_length | lower | upper | title | concat | ESCAPED_STRING | NUMBER + + round: "round(" function "," NUMBER ")" + format_length: metric_length | imperial_length + metric_length: "metric_length(" function "," NUMBER "," NUMBER ")" + imperial_length: "imperial_length(" function "," NUMBER ["," ESCAPED_STRING] ")" + lower: "lower(" function ")" + upper: "upper(" function ")" + title: "title(" function ")" + concat: "concat(" function ("," function)* ")" + + // Embed common.lark for packaging + DIGIT: "0".."9" + HEXDIGIT: "a".."f"|"A".."F"|DIGIT + INT: DIGIT+ + SIGNED_INT: ["+"|"-"] INT + DECIMAL: INT "." INT? | "." INT + _EXP: ("e"|"E") SIGNED_INT + FLOAT: INT _EXP | DECIMAL _EXP? + SIGNED_FLOAT: ["+"|"-"] FLOAT + NUMBER: FLOAT | INT + SIGNED_NUMBER: ["+"|"-"] NUMBER + _STRING_INNER: /.*?/ + _STRING_ESC_INNER: _STRING_INNER /(?. from math import pi +from fractions import Fraction prefixes = { "EXA": 1e18, diff --git a/src/ifcopenshell-python/test/util/test_selector.py b/src/ifcopenshell-python/test/util/test_selector.py index 67749417bd..650e6e2c99 100644 --- a/src/ifcopenshell-python/test/util/test_selector.py +++ b/src/ifcopenshell-python/test/util/test_selector.py @@ -22,6 +22,32 @@ import ifcopenshell.api import ifcopenshell.util.selector as subject +class TestFormat(): + def test_no_formatting(self): + assert subject.format("123") == "123" + assert subject.format('\"123\"') == "123" + assert subject.format('\"foo\"') == "foo" + + def test_string_formatting(self): + assert subject.format('upper(\"fOo\")') == "FOO" + assert subject.format('lower(\"fOo\")') == "foo" + assert subject.format('title(\"fOo\")') == "Foo" + assert subject.format('concat(\"fOo\", \"bar\")') == "fOobar" + assert subject.format('upper(concat(\"fOo\", \"bar\"))') == "FOOBAR" + + def test_number_formatting(self): + assert subject.format("round(123, 5)") == "125.0" + assert subject.format('round(\"123\", 5)') == "125.0" + assert subject.format('metric_length(123, 5, 2)') == "125.00" + assert subject.format('metric_length(123.123, 0.1, 2)') == "123.10" + assert subject.format('metric_length(\"123\", 5, 2)') == "125.00" + assert subject.format('imperial_length(1, 1)') == "1'" + assert subject.format('imperial_length(3.123, 1)') == "3' - 1\"" + assert subject.format('imperial_length(3.123, 2)') == "3' - 1 1/2\"" + assert subject.format('imperial_length(\"3.123\", 2)') == "3' - 1 1/2\"" + assert subject.format('imperial_length(\"123.123\", 2, \"inch\")') == "10' - 3\"" + + class TestGetElementValue(test.bootstrap.IFC4): def test_selecting_an_elements_class_or_id_using_a_query(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") From 9a7a284561a2af554f689f1eab58092b07fe3e62 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 26 Aug 2023 16:42:18 +1000 Subject: [PATCH 03/81] Selector element key queries now allow for regex matching, and single regex matches return that only item, not a list with one item in it. --- .../ifcopenshell/util/selector.py | 130 ++++++++++++------ 1 file changed, 86 insertions(+), 44 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index 0acd0aa44e..095a9df50e 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -52,8 +52,8 @@ filter_elements_grammar = lark.Lark( value: special | quoted_string | regex_string | unquoted_string unquoted_string: /[^.=\\s]+/ - quoted_string: ESCAPED_STRING regex_string: "/" /[^\\/]+/ "/" + quoted_string: ESCAPED_STRING special: null | true | false @@ -94,19 +94,18 @@ filter_elements_grammar = lark.Lark( ) get_element_grammar = lark.Lark( - """start: WORD | ESCAPED_STRING | keys_regex | keys_quoted | keys_simple - keys_regex: "r" ESCAPED_STRING ("." ESCAPED_STRING)* - keys_quoted: ESCAPED_STRING ("." ESCAPED_STRING)* - keys_simple: /[^\\W][^.=<>!%*\\]]*/ ("." /[^\\W][^.=<>!%*\\]]*/)* + """start: keys + + keys: key ("." key)* + key: quoted_string | regex_string | unquoted_string + unquoted_string: /[^.=\\/\\s]+/ + regex_string: "/" /[^\\/]+/ "/" + quoted_string: ESCAPED_STRING // Embed common.lark for packaging _STRING_INNER: /.*?/ _STRING_ESC_INNER: _STRING_INNER /(? Date: Sat, 26 Aug 2023 18:24:48 +1000 Subject: [PATCH 04/81] Minor fixes, and IfcCSV now uses pandas to import ODS/XLSX for more robust importing. --- src/ifccsv/ifccsv.py | 38 +++---------------- .../ifcopenshell/util/selector.py | 3 +- .../test/util/test_selector.py | 22 ++++++++++- 3 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/ifccsv/ifccsv.py b/src/ifccsv/ifccsv.py index ae5c03ef47..d8e31a2183 100755 --- a/src/ifccsv/ifccsv.py +++ b/src/ifccsv/ifccsv.py @@ -91,10 +91,6 @@ class IfcCsv: for element in elements: result = [] - for index, attribute in enumerate(attributes): - if "*" in attribute: - attributes.extend(self.get_wildcard_attributes(attribute)) - del attributes[index] for attribute in attributes: value = ifcopenshell.util.selector.get_element_value(element, attribute) @@ -262,7 +258,7 @@ class IfcCsv: reverse = sort_data["order"] == "DESC" self.results = sorted(self.results, key=lambda x: natural_sort(x[i]), reverse=reverse) else: - if include_global_id and len(self.results[0]) > 1: + if include_global_id and len(list(self.results[0])) > 1: self.results = sorted(self.results, key=lambda x: x[1]) elif not include_global_id: self.results = sorted(self.results, key=lambda x: x[0]) @@ -397,36 +393,12 @@ class IfcCsv: self.process_row(ifc_file, row, headers, attributes, null, bool_true, bool_false) def import_xlsx(self, ifc_file, table, attributes, null, bool_true, bool_false): - workbook = openpyxl.load_workbook(filename=table, read_only=True) - worksheet = workbook.active # Assuming data is on the first sheet - headers = None - - for row in worksheet.iter_rows(values_only=True): - if not headers: - headers = list(row) - if not attributes: - attributes = [None] * len(headers) - elif len(attributes) == len(headers) - 1: - attributes.insert(0, "") # The GlobalId column - continue - self.process_row(ifc_file, row, headers, attributes, null, bool_true, bool_false) + df = pd.read_excel(table) + self.import_pd(ifc_file, df, attributes, null, bool_true, bool_false) def import_ods(self, ifc_file, table, attributes, null, bool_true, bool_false): - doc = load(table) - first_sheet = doc.spreadsheet.getElementsByType(Table)[0] - rows = first_sheet.getElementsByType(TableRow) - headers = None - - for row in rows: - values = [cell.getElementsByType(P)[0].childNodes[0].data for cell in row.getElementsByType(TableCell)] - if not headers: - headers = values - if not attributes: - attributes = [None] * len(headers) - elif len(attributes) == len(headers) - 1: - attributes.insert(0, "") # The GlobalId column - continue - self.process_row(ifc_file, values, headers, attributes, null, bool_true, bool_false) + df = pd.read_excel(table, engine="odf") + self.import_pd(ifc_file, df, attributes, null, bool_true, bool_false) def import_pd(self, ifc_file, df, attributes=None, null="-", bool_true="YES", bool_false="NO"): headers = df.columns.tolist() diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index 095a9df50e..b1bf056ff7 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -808,7 +808,8 @@ class Selector: value = len(list(value)) elif isinstance(value, (list, tuple)): value = len(value) - value = 1 + else: + value = 1 elif key == "class": value = value.is_a() elif key == "id": diff --git a/src/ifcopenshell-python/test/util/test_selector.py b/src/ifcopenshell-python/test/util/test_selector.py index 650e6e2c99..a63a8fdfb2 100644 --- a/src/ifcopenshell-python/test/util/test_selector.py +++ b/src/ifcopenshell-python/test/util/test_selector.py @@ -78,7 +78,7 @@ class TestGetElementValue(test.bootstrap.IFC4): assert subject.get_element_value(element, "material.item.Name.0") == "L1" assert subject.get_element_value(element, "material.item.Name.1") == "L2" assert subject.get_element_value(element, '"material"."item"."Name"') == ["L1", "L2"] - assert subject.get_element_value(element, 'r"material"."item"."Name"') == ["L1", "L2"] + assert subject.get_element_value(element, 'material."item"."Name"') == ["L1", "L2"] # Provide shortform for convenience assert subject.get_element_value(element, "mat.i.Name") == ["L1", "L2"] @@ -86,7 +86,7 @@ class TestGetElementValue(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") assert subject.get_element_value(element, "material.item.Name.0") is None - def test_selceting_a_list_item_that_fails_silently(self): + def test_selecting_a_list_item_that_fails_silently(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") material2 = ifcopenshell.api.run("material.add_material", self.file, name="CON02") @@ -99,6 +99,24 @@ class TestGetElementValue(test.bootstrap.IFC4): assert subject.get_element_value(element, "material.item.Name.0") == "L1" assert subject.get_element_value(element, "material.item.Name.1") is None + def test_selecting_a_pset(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Foobar") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Foo": "Bar"}) + assert subject.get_element_value(element, "Foobar.Foo") == "Bar" + assert subject.get_element_value(element, "Foobar./F.*/") == "Bar" + assert subject.get_element_value(element, "/Foo.*/./F.*/") == "Bar" + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Baz": 123}) + assert subject.get_element_value(element, "/Foo.*/./B.*/") == 123 + assert subject.get_element_value(element, "/Foo.*/./.*/") == ["Bar", 123] + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Bay": 123.3}) + assert subject.get_element_value(element, "/Foo.*/./B.*/") == [123, 123.3] + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Pset_WallCommon") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Status": ["New"]}) + assert subject.get_element_value(element, "/Pset_.*Common/.Status") == ["New"] + assert subject.get_element_value(element, "/Pset_.*Common/.Status.0") == "New" + class TestFilterElements(test.bootstrap.IFC4): def test_selecting_by_globalid(self): From 3c23a5713844019e8773e623303b508223a24e33 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 26 Aug 2023 18:26:03 +1000 Subject: [PATCH 05/81] Minor fix to use new regex syntax in select similar dialog. --- src/blenderbim/blenderbim/bim/module/search/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/bim/module/search/data.py b/src/blenderbim/blenderbim/bim/module/search/data.py index b34d80148f..9907ea8f85 100644 --- a/src/blenderbim/blenderbim/bim/module/search/data.py +++ b/src/blenderbim/blenderbim/bim/module/search/data.py @@ -104,7 +104,7 @@ class SelectSimilarData: psets = ifcopenshell.util.element.get_psets(element, psets_only=True) for pset, properties in psets.items(): if pset.endswith("Common"): - keys.extend([f'r".*Common"."{name}"' for name in properties.keys() if name != "id"]) + keys.extend([f'/.*Common/."{name}"' for name in properties.keys() if name != "id"]) else: keys.extend([f"{pset}.{name}" for name in properties.keys() if name != "id"]) return [(k, k, "") for k in keys] From 38a9e291026abb31d571b5af603f68592a365a9a Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 26 Aug 2023 22:11:54 +1000 Subject: [PATCH 06/81] Bump IOS and enable unify inputs. --- src/blenderbim/Makefile | 2 +- .../blenderbim/bim/module/drawing/operator.py | 1 + src/ifcopenshell-python/Makefile | 2 +- .../docs/ifcconvert/installation.rst | 10 ++-- .../docs/ifcopenshell-python/installation.rst | 56 +++++++++---------- 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/blenderbim/Makefile b/src/blenderbim/Makefile index ac0e7b3c88..64f78f0581 100644 --- a/src/blenderbim/Makefile +++ b/src/blenderbim/Makefile @@ -171,7 +171,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-dcc9d0e-$(PLATFORM)64.zip + cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-dadcbe6-$(PLATFORM)64.zip cd dist/working && unzip ifcopenshell-python* cp -r dist/working/ifcopenshell dist/blenderbim/libs/site/packages/ diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 232b845518..9ca530ea86 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -853,6 +853,7 @@ class CreateDrawing(bpy.types.Operator): self.serialiser.setScale(self.scale) self.serialiser.setSubtractionSettings(ifcopenshell.ifcopenshell_wrapper.ALWAYS) self.serialiser.setUsePrefiltering(True) # See #3359 + self.serialiser.setUnifyInputs(True) if target_view == "REFLECTED_PLAN_VIEW": self.serialiser.setMirrorY(True) # tree = ifcopenshell.geom.tree() diff --git a/src/ifcopenshell-python/Makefile b/src/ifcopenshell-python/Makefile index 83e1d840e7..db0d62e3ff 100644 --- a/src/ifcopenshell-python/Makefile +++ b/src/ifcopenshell-python/Makefile @@ -103,7 +103,7 @@ endif mkdir -p dist/ifcopenshell cp -r ifcopenshell/* dist/ifcopenshell/ - cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-dcc9d0e-$(PLATFORM)64.zip + cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-dadcbe6-$(PLATFORM)64.zip cd dist/working && unzip ifcopenshell-python* cp -r dist/working/ifcopenshell/ifcopenshell_wrapper.py dist/ifcopenshell/ ifeq ($(PLATFORM), win) diff --git a/src/ifcopenshell-python/docs/ifcconvert/installation.rst b/src/ifcopenshell-python/docs/ifcconvert/installation.rst index b69e2244da..f0f713c1e8 100644 --- a/src/ifcopenshell-python/docs/ifcconvert/installation.rst +++ b/src/ifcopenshell-python/docs/ifcconvert/installation.rst @@ -20,11 +20,11 @@ Pre-built packages | build-linux64_ | build-win32_ | build-win64_ | build-macos64_ | build-macosm164_ | +----------------+----------------+----------------+----------------+------------------+ -.. _build-linux64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dcc9d0e-linux64.zip -.. _build-win32: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dcc9d0e-win32.zip -.. _build-win64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dcc9d0e-win64.zip -.. _build-macos64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dcc9d0e-macos64.zip -.. _build-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dcc9d0e-macosm164.zip +.. _build-linux64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-linux64.zip +.. _build-win32: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-win32.zip +.. _build-win64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-win64.zip +.. _build-macos64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-macos64.zip +.. _build-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-macosm164.zip 2. Unzip the downloaded file and run IfcConvert using the command line. diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst b/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst index 83552ffb0a..0d7439ff03 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst @@ -40,34 +40,34 @@ changes in the IfcOpenShell C++ core. | Python 3.11 | py311-linux64_ | py311-win32_ | py311-win64_ | N/A | py311-macosm164_ | +-------------+----------------+----------------+----------------+----------------+------------------+ -.. _py36-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dcc9d0e-linux64.zip -.. _py37-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dcc9d0e-linux64.zip -.. _py38-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dcc9d0e-linux64.zip -.. _py39-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dcc9d0e-linux64.zip -.. _py310-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dcc9d0e-linux64.zip -.. _py311-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dcc9d0e-linux64.zip -.. _py36-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dcc9d0e-win32.zip -.. _py37-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dcc9d0e-win32.zip -.. _py38-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dcc9d0e-win32.zip -.. _py39-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dcc9d0e-win32.zip -.. _py310-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dcc9d0e-win32.zip -.. _py311-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dcc9d0e-win32.zip -.. _py36-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dcc9d0e-win64.zip -.. _py37-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dcc9d0e-win64.zip -.. _py38-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dcc9d0e-win64.zip -.. _py39-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dcc9d0e-win64.zip -.. _py310-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dcc9d0e-win64.zip -.. _py311-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dcc9d0e-win64.zip -.. _py36-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dcc9d0e-macos64.zip -.. _py37-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dcc9d0e-macos64.zip -.. _py38-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dcc9d0e-macos64.zip -.. _py39-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dcc9d0e-macos64.zip -.. _py310-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dcc9d0e-macos64.zip -.. _py37-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dcc9d0e-macosm164.zip -.. _py38-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dcc9d0e-macosm164.zip -.. _py39-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dcc9d0e-macosm164.zip -.. _py310-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dcc9d0e-macosm164.zip -.. _py311-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dcc9d0e-macosm164.zip +.. _py36-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dadcbe6-linux64.zip +.. _py37-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-linux64.zip +.. _py38-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-linux64.zip +.. _py39-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-linux64.zip +.. _py310-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-linux64.zip +.. _py311-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dadcbe6-linux64.zip +.. _py36-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dadcbe6-win32.zip +.. _py37-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-win32.zip +.. _py38-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-win32.zip +.. _py39-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-win32.zip +.. _py310-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-win32.zip +.. _py311-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dadcbe6-win32.zip +.. _py36-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dadcbe6-win64.zip +.. _py37-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-win64.zip +.. _py38-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-win64.zip +.. _py39-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-win64.zip +.. _py310-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-win64.zip +.. _py311-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dadcbe6-win64.zip +.. _py36-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dadcbe6-macos64.zip +.. _py37-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-macos64.zip +.. _py38-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-macos64.zip +.. _py39-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-macos64.zip +.. _py310-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-macos64.zip +.. _py37-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-macosm164.zip +.. _py38-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-macosm164.zip +.. _py39-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-macosm164.zip +.. _py310-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-macosm164.zip +.. _py311-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dadcbe6-macosm164.zip 2. Unzip the downloaded file and copy the ``ifcopenshell`` directory into your Python path. If you're not sure where your Python path is, run the following From 13f64fdfe29828842838a6a36b2cbe0d35b8f001 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 27 Aug 2023 22:32:31 +1000 Subject: [PATCH 07/81] Write documentation describing facet selector and element query syntax. --- .../docs/ifcopenshell-python.rst | 1 + .../ifcopenshell-python/selector_syntax.rst | 230 ++++++++++++++++++ .../ifcopenshell/util/selector.py | 14 +- 3 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python.rst b/src/ifcopenshell-python/docs/ifcopenshell-python.rst index ddaa9a33eb..0861a2b374 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell-python.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell-python.rst @@ -15,4 +15,5 @@ system, as well as high level analysis and authoring functions. ifcopenshell-python/geometry_processing ifcopenshell-python/geometry_creation ifcopenshell-python/geometry_tree + ifcopenshell-python/selector_syntax ifcopenshell-python/developer_guide diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst b/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst new file mode 100644 index 0000000000..e3775e8d02 --- /dev/null +++ b/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst @@ -0,0 +1,230 @@ +Selector syntax +=============== + +A common task in querying IFC models is to filter or search for elements which +match particular criteria. For example, you might want to find all plasterboard +walls with a 2 hour fire rating on level 3. + +Alternatively, you might want to fetch some data about a single element. For +example, you might want to fetch the fire rating property of an element, or the +type description of an element, or the net volume of a list of elements. + +Once you've retreived your data, you might want to format it in some way. You +might want to ensure that all names are always uppercase. Or you might want to +take length values defined in feet, and apply imperial formatting such that it +shows both feet and inches including fractions. + +These three usecases of filtering, getting a value, and formatting that value +are common and used in many utilities, such as in the BlenderBIM Add-on, +IfcCSV, IfcDiff, IfcClash, IfcPatch, and IfcFM. + +IfcOpenShell provides a custom syntax to consistently and concisely describe +filters, value queries, and formatting rules. + +Filtering elements +------------------ + +Filtering is typically used to select any IFC element or type. + +.. code-block:: python + + import ifcopenshell + import ifcopenshell.util.selector + + model = ifcopenshell.open("model.ifc") + # Get all concrete walls and slabs. + ifcopenshell.util.selector.filter_elements(model, "IfcWall, IfcSlab, material=concrete") + +.. csv-table:: + :header: "Example Query", "Description" + + "``IfcElement``", "All physical IfcElements including subclasses like walls, doors, windows, etc. Yep, that's it! Nothing else. Literally just ``IfcElement``." + "``IfcWall, IfcSlab``", "All walls and slabs. Technically, this is either a wall or a slab, but it's easier to describe it as all walls and slabs" + "``IfcWall, IfcSlab, material=concrete``", "All walls made out of concrete and slabs made out of concrete. The material checks any assigned IfcMaterial with a matching name or category attribute." + + "``325Q7Fhnf67OZC$$r43uzK``", "A single element. Yep, just the GlobalId, nothing else! Easy." + + "``325Q7Fhnf67OZC$$r43uzK, 2VlJ7nbF5AFfQQuRvSWexT``", "A bunch of arbitrary elements." + + "``IfcWall, ! 325Q7Fhnf67OZC$$r43uzK``", "All walls except that one element." + + "``IfcElement, ! IfcWall``", "All elements except for walls." + + "``IfcDoor, Name=D01``", "Any doors named D01, notice how attributes match the IFC Attribute naming exactly" + + "``IfcDoor, Name=/D[0-9]{2}/``", "Any doors with the naming scheme of D followed by two numbers:" + + "``IfcWall, Pset_WallCommon.FireRating=2HR``", "Any 2 hour fire rated wall" + + "``IfcWall, IfcColumn, IfcBeam, IfcFooting, /Pset_.*Common/.LoadBearing=TRUE``", "Any load bearing structure" + + "``IfcElement, /Pset_.*Common/.FireRating != NULL``", "Any element with a fire rating property" + + "``IfcWall, type=WT01, location=""Level 3""``", "Any walls of wall type WT01 on level 3 (we quote Level 3 since it has a space)" + + "``IfcElement, classification=/Pr_.*/``", "Any maintainable product according to Uniclass tables" + + "``IfcWall, IfcSlab, ! 325Q7Fhnf67OZC$$r43uzK, material=concrete, /Pset_.*Common/.FireRating=2HR``", "Notice how there are intuitive rules that class and instance filters are OR whereas other filters are AND So here is any wall or slab except that one element that has a material of concrete and has a 2 hour fire rating" + + "``IfcSlab, material=concrete + IfcDoor``", "Finally, you can union facet lists together. So here is all concrete slabs, as well as all doors (regardless of concrete)" + + "``IfcDoor, IfcWindow + IfcWall, IfcSlab, material=concrete + 325Q7Fhnf67OZC$$r43uzK``", "Here's another example of unioning facet groups. All doors and window, and all concrete walls and slabs, plus that one random element" + + "``IfcPump, location=""Level 3""``", "Locations bubble up the hierarchy. So if a pump is in a space and that space is on Level 3, then you can say ""all pumps on level 3"" which will include that pump in the space." + +The filter elements syntax works by specifying one or more groups of filters +separated by a ``+`` character. Each filter group will return a set of filtered +elements, and these are unioned together. + +.. code-block:: + + filter_group[ + filter_group]* + +A filter group consists of one or more filters separated by a ``,`` character. +The filters are chained and apply from left to right. + +.. code-block:: + + filter[, filter]* + +There are nine types of filters to choose from. Some of these filters will add +new elements to your filter group, and some will filter previously added +elements in your filter group based on their criteria. + +.. csv-table:: + :header: "Filter", "Type", "Usage", "Example" + + "Class", "Add", "``[!] {{ifc_class_name}}``", "``IfcWall`` adds all IfcWall elements and their subclasses. ``! IfcWall`` subtracts all non-IfcWall elements from the filter group." + "GlobalId", "Add", "``[!] {{global_id}}``", "``325Q7Fhnf67OZC$$r43uzK`` adds the single element with that GlobalId attribute. ``! 325Q7Fhnf67OZC$$r43uzK`` subtracts that single element." + "Attribute", "Filter", "``{{name}}{{=}}{{value}}``", "``Name=Foo`` specifies the criteria that elements must have a ``Name`` attribute with a value of ``Foo``. Attribute names must be spelled exactly the same as in IFC, which means that they must start with an uppercase character." + "Property", "Filter", "``{{pset}}.{{prop}}{{=}}{{value}}``", "``Pset_WallCommon.FireRating=2HR`` specifies the criteria that elements must have a ``Pset_WallCommon`` property set, with a ``FireRating`` property within it with a value of ``2HR``. The property set name and the property name are separated by a ``.``." + "Type", "Filter", "``type{{=}}{{value}}``", "``type=Foo`` specifies the criteria that elements must have a type which has a ``Name`` attribute with a value of ``Foo``." + "Material", "Filter", "``material{{=}}{{value}}``", "``material=Foo`` specifies the criteria that elements must have a IfcMaterial assigned directly or indirectly (such as within a layer set). That IfcMaterial must have either a ``Name`` or ``Category`` attribute with a value of ``Foo``." + "Classification", "Filter", "``classification{{=}}{{value}}``", "``classification=Foo`` specifies the criteria that elements must have an IfcClassificationReference with an ``Identification`` attribute with a value of ``Foo``." + "Location", "Filter", "``location{{=}}{{value}}``", "``location=Foo`` specifies the criteria that elements must be contained directly or indirectly in a spatial element with a ``Name`` attribute with a value of ``Foo``." + "Query", "Filter", "``query:{{keys}}{{=}}{{value}}``", "``query:types.count=0`` specifies the criteria that elements must have zero type occurrences. The query keys corresponds to the syntax used in the `Getting element values`_ section" + +When you specify a filter with a ``{{=}}`` check, you can choose from one of +the following comparison checks: + +.. csv-table:: + :header: "Comparison", "Description" + + "``=``", "Must equal the value. The data type of the value is automatically converted to match." + "``!=``", "Must not equal the value." + "``>``", "Must be greater than the value." + "``>=``", "Must be greater than or equal to the value." + "``<``", "Must be less than the value." + "``<=``", "Must be less than or equal to the value." + +When you specify a ``{{pset}}``, ``{{prop}}``, or ``{{value}}``, there are +three ways you can do so: + +.. csv-table:: + :header: "Value Type", "Example", "Description" + + "Quoted string", "``""foo \""bar\"" baz""``", "The value must be in double quotes. The value may contain spaces, symbols, and other characters. If you need to use a double quote, you can escape it with a backslash. This is the safest, most general way to specify a value." + "Unquoted string", "``foobarbaz``", "For convenience, if you have a simple value which contains no spaces or special characters, you are free to specify it as an unquoted string." + "Regex string", "``/foo.*baz/``", "You may specify a Python-compatible regex pattern delimited by forward slashes." + +Getting element values +---------------------- + +Given a single element, this syntax provides a simple way to extract a value +without needing to write complex code for it. + +.. code-block:: python + + import ifcopenshell + import ifcopenshell.util.selector + + # Get the Name attribute of the wall's type. + ifcopenshell.util.selector.get_element_value(wall, "type.Name") + +.. csv-table:: + :header: "Example Query", "Description" + + "``class``", "Get the IFC class of the element." + "``Name``", "Get the ``Name`` attribute." + "``Pset_WallCommon.Status``", "Get the value of the ``Status`` property in the ``Pset_WallCommon`` property set." + "``/Pset_.*Common/.Status``", "Get the value of the ``Status`` property in the any common property set." + "``type.Name``", "Get the ``Name`` attribute of the element's relating type." + "``types.count``", "Count the number of occurrences of a type." + "``storey.Name``", "Get the ``Name`` attribute of the storey that the element is contained in." + "``materials.count``", "Count the number of materials assigned to an element." + "``material.Name``", "Get the name of the assigned material." + "``material.item.0.Name``", "Get the name of the first item in a material set (e.g. the first material layer)" + +The element value syntax works by specifying one or more query keys separated +by a ``.`` character. Each query key returns data based of the results of the +previous key. + +.. code-block:: + + key[.key]* + +Valid keys are: + +.. csv-table:: + :header: "Key", "Description" + + "``id``", "Gets the IFC ID (equivalent to ``.id()``)" + "``class``", "Gets the IFC class (equivalent to ``.is_a()``)" + "``predefined_type``", "Gets the predefined type of the element, taking into account inheritance." + "``{{attribute}}``", "Gets the value of the attribute you specify. Attributes always start with an uppercase letter." + "``{{pset}}``", "This gets the property set with the same name specified in ``{{pset}}``. Note that this can be ambiguous with ``{{attribute}}``. If there is an ambiguity, ``{{attribute}}`` takes priority." + "``{{prop}}``", "If the previous key returns a property set, ``{{prop}}`` gets the value of a property with the same name specified in ``{{prop}}``. For this reason, often you specify both keys together, like this: ``{{pset}}.{{prop}}``." + "``type``", "Gets the relating type of an element occurrence." + "``types`` or ``occurrences``", "Gets the related objects of an element type." + "``container``", "Gets the immediate spatial element that an element is contained in." + "``space``", "Gets the first IfcSpace spatial element that an element is contained in." + "``storey``", "Gets the first IfcBuildingStorey spatial element that an element is contained in." + "``building``", "Gets the first IfcBuilding spatial element that an element is contained in." + "``site``", "Gets the first IccSite spatial element that an element is contained in." + "``material`` or ``mat``", "Gets the assigned material, which may be a material set." + "``item`` or ``i``", "If the previous key returns a material set, gets the relevant material set items" + "``materials`` or ``mats``", "Gets a list of IfcMaterials assigned directly or indirectly (such as via a material set) to the element" + "``count``", "If the previous key returns multiple things, count that list. Otherwise, return 1." + "``{{number}}``", "If the previous key returns multiple things, fetch the ``{{number}}`` index (e.g. 0, 1, 2, 3, etc) item in that list." + +When you specify a ``{{pset}}`` or ``{{prop}}``, there are three ways you can +do so: + +.. csv-table:: + :header: "Value Type", "Example", "Description" + + "Quoted string", "``""foo \""bar\"" baz""``", "The value must be in double quotes. The value may contain spaces, symbols, and other characters. If you need to use a double quote, you can escape it with a backslash. This is the safest, most general way to specify a value." + "Unquoted string", "``foobarbaz``", "For convenience, if you have a simple value which contains no spaces or special characters, you are free to specify it as an unquoted string." + "Regex string", "``/foo.*baz/``", "You may specify a Python-compatible regex pattern delimited by forward slashes." + +Formatting +---------- + +Given a value, this syntax allows a simple way to specify a set of formatting +rules. This is useful for configuring outputs of how data should be presented. + +.. code-block:: python + + import ifcopenshell + import ifcopenshell.util.selector + + # Get the Name attribute of the wall's type. + value = ifcopenshell.util.selector.get_element_value(wall, "type.Name") + # Always display names in uppercase. + ifcopenshell.util.selector.format(f'upper("{value}")') + +Formatting queries are written similar to how you'd write functions or formulas +in spreadsheets. For example ``upper("foo")`` will produce ``FOO``. You may +nest formulas, for example ``concat(title("foo"), lower("Bar"))`` will produce +``Foobar``. Strings must be double quoted. + +.. csv-table:: + :header: "Function", "Example", "Result", "Description" + + "``upper({{value}})``", "``upper(""Foo"")``", "``FOO``", "Uppercases a string." + "``lower({{value}})``", "``lower(""Foo"")``", "``foo``", "Lowercases a string." + "``title({{value}})``", "``title(""foo"")``", "``Foo``", "Titlecases a string." + "``concat({{value}}[, {{value2}}]*)``", "``concat(""foo"", ""bar"")``", "``foobar``", "Concatenates two or more strings." + "``round({{value}}, {{precision}})``", "``round(3.123, 0.1)``", "``3.1``", "Rounds ``{{value}}`` to the nearest ``{{precision}}``." + "``metric_length({{value}}, {{precision}}, {{decimals}})``", "``metric_length(3.123, 0.1, 2)``", "``3.10``", "Rounds ``{{value}}`` to the nearest ``{{precision}}`` then displays using a certain amount of decimal places." + "``imperial_length({{value}}, {{precision}}, {{unit}})``", "``imperial_length(3.22, 4, ""foot"")``", "``3' - 3 3/4""``", "Rounds ``{{value}}`` to the nearest ``1/{{precision}}`` inch then displays using fractional feet and inches. The ``{{value}}`` may be specified either as ``foot`` or ``inch`` depending on ``{{unit}}``." diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index b1bf056ff7..e88dfac47b 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -794,15 +794,15 @@ class Selector: elif key == "container": value = ifcopenshell.util.element.get_container(value) elif key == "space": - value = ifcopenshell.util.element.get_container(element, ifc_class="IfcSpace") + value = ifcopenshell.util.element.get_container(value, ifc_class="IfcSpace") elif key == "storey": - value = ifcopenshell.util.element.get_container(element, ifc_class="IfcBuildingStorey") + value = ifcopenshell.util.element.get_container(value, ifc_class="IfcBuildingStorey") elif key == "building": - value = ifcopenshell.util.element.get_container(element, ifc_class="IfcBuilding") + value = ifcopenshell.util.element.get_container(value, ifc_class="IfcBuilding") elif key == "site": - value = ifcopenshell.util.element.get_container(element, ifc_class="IfcSite") - elif key == "types": - value = ifcopenshell.util.element.get_types(element) + value = ifcopenshell.util.element.get_container(value, ifc_class="IfcSite") + elif key in ("types", "occurrences"): + value = ifcopenshell.util.element.get_types(value) elif key == "count": if isinstance(value, set): value = len(list(value)) @@ -812,6 +812,8 @@ class Selector: value = 1 elif key == "class": value = value.is_a() + elif key == "predefined_type": + value = ifcopenshell.util.element.get_predefined_type(value) elif key == "id": value = value.id() elif isinstance(value, ifcopenshell.entity_instance): From 1a8f2be4fdcc8c50d6847d3f3aa332ce8972a987 Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:19:33 +0100 Subject: [PATCH 08/81] Move grids panel under Project Setup --- src/blenderbim/blenderbim/bim/module/model/ui.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/ui.py b/src/blenderbim/blenderbim/bim/module/model/ui.py index 9ff0b0a282..6a0b8005f8 100644 --- a/src/blenderbim/blenderbim/bim/module/model/ui.py +++ b/src/blenderbim/blenderbim/bim/module/model/ui.py @@ -156,15 +156,14 @@ class BIM_PT_authoring(Panel): class BIM_PT_Grids(Panel): bl_label = "Grids" bl_idname = "BIM_PT_Grids" - bl_space_type = "VIEW_3D" - bl_region_type = "UI" bl_options = {"DEFAULT_CLOSED"} - bl_category = "BlenderBIM" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_parent_id = "BIM_PT_project_setup" def draw(self, context): - self.animation_props = context.scene.BIMAnimationProperties - row = self.layout.row() - row.operator("mesh.add_grid", icon="ADD", text="Add Grids") + self.layout.row().operator("mesh.add_grid", icon="ADD", text="Add Grids") class BIM_PT_array(bpy.types.Panel): From 9944c7d2dee1d4b596accdc4489d0a2b98ac8dd7 Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:21:19 +0100 Subject: [PATCH 09/81] you can now reload linked IFCs #3652 --- .../blenderbim/bim/module/project/__init__.py | 1 + .../blenderbim/bim/module/project/operator.py | 17 +++++++++++++++++ .../blenderbim/bim/module/project/ui.py | 2 ++ 3 files changed, 20 insertions(+) diff --git a/src/blenderbim/blenderbim/bim/module/project/__init__.py b/src/blenderbim/blenderbim/bim/module/project/__init__.py index 3fe18e7f2f..977bc54c64 100644 --- a/src/blenderbim/blenderbim/bim/module/project/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/project/__init__.py @@ -47,6 +47,7 @@ classes = ( operator.UnlinkIfc, operator.UnloadLink, operator.UnloadProject, + operator.ReloadLink, prop.LibraryElement, prop.FilterCategory, prop.Link, diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index b510494fd7..fa70a93fcf 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -880,6 +880,23 @@ class LoadLink(bpy.types.Operator): return {"FINISHED"} +class ReloadLink(bpy.types.Operator): + bl_idname = "bim.reload_link" + bl_label = "Reload Link" + bl_options = {"REGISTER", "UNDO"} + bl_description = "Reload the selected file" + filepath: bpy.props.StringProperty() + + def execute(self, context): + def get_linked_ifc(): + selected_filename = os.path.basename(self.filepath) + return [c for c in bpy.data.collections if "IfcProject" in c.name and c.library and os.path.basename(c.library.filepath) == selected_filename] + + for linked_ifc in get_linked_ifc: + linked_ifc.reload() + return {"FINISHED"} + + class ToggleLinkSelectability(bpy.types.Operator): bl_idname = "bim.toggle_link_selectability" bl_label = "Toggle Link Selectability" diff --git a/src/blenderbim/blenderbim/bim/module/project/ui.py b/src/blenderbim/blenderbim/bim/module/project/ui.py index e0a2eea7e5..8b61c4320d 100644 --- a/src/blenderbim/blenderbim/bim/module/project/ui.py +++ b/src/blenderbim/blenderbim/bim/module/project/ui.py @@ -375,6 +375,8 @@ class BIM_UL_links(UIList): op.mode = "VISIBLE" op = row.operator("bim.unload_link", text="", icon="UNLINKED") op.filepath = item.name + op = row.operator("bim.reload_link", text="", icon="FILE_REFRESH") + op.filepath = item.name else: row.prop(item, "name", text="") op = row.operator("bim.load_link", text="", icon="LINKED") From ad420108b0ca608b30b7c173f25d6969022c7c5c Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:43:33 +0100 Subject: [PATCH 10/81] run black and fix silly code #3652 --- .../blenderbim/bim/module/project/operator.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index fa70a93fcf..aa1c2309e9 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -888,12 +888,15 @@ class ReloadLink(bpy.types.Operator): filepath: bpy.props.StringProperty() def execute(self, context): - def get_linked_ifc(): + def get_linked_ifcs(): selected_filename = os.path.basename(self.filepath) - return [c for c in bpy.data.collections if "IfcProject" in c.name and c.library and os.path.basename(c.library.filepath) == selected_filename] - - for linked_ifc in get_linked_ifc: - linked_ifc.reload() + return [ + c.library + for c in bpy.data.collections + if "IfcProject" in c.name and c.library and os.path.basename(c.library.filepath) == selected_filename + ] + for library in get_linked_ifcs() or []: + library.reload() return {"FINISHED"} @@ -1054,6 +1057,7 @@ class ExportIFC(bpy.types.Operator): settings.json_compact = self.json_compact ifc_exporter = export_ifc.IfcExporter(settings) + print("Starting export") settings.logger.info("Starting export") ifc_exporter.export() settings.logger.info("Export finished in {:.2f} seconds".format(time.time() - start)) From 55a623dc97a8497ac5523e496d880e1bb579f07a Mon Sep 17 00:00:00 2001 From: Chetan Date: Fri, 25 Aug 2023 09:45:30 +0800 Subject: [PATCH 11/81] Give each accessor its own buffer view to improve the memory and rendering efficiency of the glb file --- src/serializers/GltfSerializer.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/serializers/GltfSerializer.cpp b/src/serializers/GltfSerializer.cpp index ffebf97935..cd667c6d72 100644 --- a/src/serializers/GltfSerializer.cpp +++ b/src/serializers/GltfSerializer.cpp @@ -121,17 +121,28 @@ const uint32_t component_type::value = CT_UNSIGNED_INT; template <> const uint32_t component_type::value = CT_FLOAT; +static int bufferViewId = 0; + template size_t write_accessor(json& j, std::ofstream& ofs, It begin, It end) { auto num = std::distance(begin, end) / N; json accessor = json::object(); - accessor["bufferView"] = N == 1 ? 0 : 1; - accessor["byteOffset"] = (size_t)ofs.tellp(); + accessor["bufferView"] = bufferViewId; + accessor["byteOffset"] = 0; accessor["componentType"] = component_type::value; accessor["count"] = num; + if (N == 1) { + j["bufferViews"].push_back({ {"buffer", 0}, {"byteOffset", (size_t)ofs.tellp()}, { "byteLength", num * 4}, {"target", 34963} }); + } + else { + j["bufferViews"].push_back({ {"buffer", 0}, {"byteStride", 12}, { "byteOffset", (size_t)ofs.tellp()}, { "byteLength", num * 12}, {"target", 34962}}); + } + + bufferViewId++; + std::array min, max; min.fill(std::numeric_limits::max()); max.fill(std::numeric_limits::lowest()); @@ -325,8 +336,12 @@ void GltfSerializer::finalize() { json scene_0; scene_0["nodes"] = node_array_; json_["scenes"].push_back(scene_0); - json_["bufferViews"].push_back({ {"buffer", 0}, { "byteLength", indices_length } }); - json_["bufferViews"].push_back({ {"buffer", 0}, {"byteStride", 12}, { "byteOffset", indices_length }, { "byteLength", binary_length - indices_length } }); + + for (auto &n : json_["bufferViews"]) { + if (n.contains("byteStride")) + n["byteOffset"] = (int)n["byteOffset"] + indices_length; + } + json_["buffers"].push_back({ {"byteLength", binary_length} }); std::string json_contents = json_.dump(); From c483116b32e0541d0c3a59eed72d72ac525bfb29 Mon Sep 17 00:00:00 2001 From: Chetan Date: Mon, 28 Aug 2023 13:54:21 +0800 Subject: [PATCH 12/81] Create constants ELEMENT_ARRAY_BUFFER and ARRAY_BUFFER to allow for more descriptive bufferview construction. Change the bufferViewId variable from a static variable to a member variable because python instances of IfcOpenShell can have multiple serializers open at any given time. This commit also includes some minor code reformatting and code comments explaining the changes done. Finally integer constants GLB_FILE_HEAER, GLB_JSON_HEADER, GLB_BINARY_CHUNK_HEADER were added to make the glb file header creation more descriptive --- src/serializers/GltfSerializer.cpp | 36 ++++++++++++++++++++---------- src/serializers/GltfSerializer.h | 2 ++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/serializers/GltfSerializer.cpp b/src/serializers/GltfSerializer.cpp index cd667c6d72..3c285b7c03 100644 --- a/src/serializers/GltfSerializer.cpp +++ b/src/serializers/GltfSerializer.cpp @@ -44,6 +44,9 @@ static const uint32_t PRIM_TRIANGLES = 4; static const uint32_t PRIM_TRIANGLE_STRIP = 5; static const uint32_t PRIM_TRIANGLE_FAN = 6; +static const uint32_t ELEMENT_ARRAY_BUFFER = 34963; +static const uint32_t ARRAY_BUFFER = 34962; + GltfSerializer::GltfSerializer(const std::string& filename, const SerializerSettings& settings) : WriteOnlyGeometrySerializer(settings) , filename_(filename) @@ -52,6 +55,7 @@ GltfSerializer::GltfSerializer(const std::string& filename, const SerializerSett , fstream_(IfcUtil::path::from_utf8(filename).c_str(), std::ios_base::binary) , tmp_fstream1_(IfcUtil::path::from_utf8(tmp_filename1_).c_str(), std::ios_base::binary) , tmp_fstream2_(IfcUtil::path::from_utf8(tmp_filename2_).c_str(), std::ios_base::binary) + , bufferViewId(0) {} GltfSerializer::~GltfSerializer() { @@ -121,10 +125,9 @@ const uint32_t component_type::value = CT_UNSIGNED_INT; template <> const uint32_t component_type::value = CT_FLOAT; -static int bufferViewId = 0; template -size_t write_accessor(json& j, std::ofstream& ofs, It begin, It end) { +size_t write_accessor(json& j, std::ofstream& ofs, It begin, It end, int bufferViewId) { auto num = std::distance(begin, end) / N; json accessor = json::object(); @@ -135,13 +138,11 @@ size_t write_accessor(json& j, std::ofstream& ofs, It begin, It end) { accessor["count"] = num; if (N == 1) { - j["bufferViews"].push_back({ {"buffer", 0}, {"byteOffset", (size_t)ofs.tellp()}, { "byteLength", num * 4}, {"target", 34963} }); - } - else { - j["bufferViews"].push_back({ {"buffer", 0}, {"byteStride", 12}, { "byteOffset", (size_t)ofs.tellp()}, { "byteLength", num * 12}, {"target", 34962}}); + j["bufferViews"].push_back({ {"buffer", 0}, {"byteOffset", (size_t)ofs.tellp()}, { "byteLength", num * 4}, {"target", ELEMENT_ARRAY_BUFFER} }); + } else { + j["bufferViews"].push_back({ {"buffer", 0}, {"byteStride", 12}, { "byteOffset", (size_t)ofs.tellp()}, { "byteLength", num * 12}, {"target", ARRAY_BUFFER}}); } - bufferViewId++; std::array min, max; min.fill(std::numeric_limits::max()); @@ -244,16 +245,16 @@ void GltfSerializer::write(const IfcGeom::TriangulationElement* o) { json primitive = json::object(); - primitive["indices"] = write_accessor<1U>(json_, tmp_fstream1_, idx_transformed.begin(), idx_transformed.end()); + primitive["indices"] = write_accessor<1U>(json_, tmp_fstream1_, idx_transformed.begin(), idx_transformed.end(), bufferViewId++); auto vbegin = o->geometry().verts().begin(); std::vector vf(vbegin + idx_begin * 3, vbegin + idx_end * 3); - primitive["attributes"]["POSITION"] = write_accessor<3U>(json_, tmp_fstream2_, vf.begin(), vf.end()); + primitive["attributes"]["POSITION"] = write_accessor<3U>(json_, tmp_fstream2_, vf.begin(), vf.end(), bufferViewId++); if (o->geometry().normals().size()) { auto nbegin = o->geometry().normals().begin(); std::vector nf(nbegin + idx_begin * 3, nbegin + idx_end * 3); - primitive["attributes"]["NORMAL"] = write_accessor<3U>(json_, tmp_fstream2_, nf.begin(), nf.end()); + primitive["attributes"]["NORMAL"] = write_accessor<3U>(json_, tmp_fstream2_, nf.begin(), nf.end(), bufferViewId++); } primitive["material"] = writeMaterial(o->geometry().materials()[*mid0]); @@ -337,9 +338,13 @@ void GltfSerializer::finalize() { scene_0["nodes"] = node_array_; json_["scenes"].push_back(scene_0); + //The generated glb file will contain the indices buffer followed by the vertices buffer. + //Therefore once we know the size of the indices buffer, we update our vertices buffer + //to have an offset equal to the size of the indices buffer. for (auto &n : json_["bufferViews"]) { - if (n.contains("byteStride")) + if (n.contains("byteStride")) { n["byteOffset"] = (int)n["byteOffset"] + indices_length; + } } json_["buffers"].push_back({ {"byteLength", binary_length} }); @@ -347,16 +352,23 @@ void GltfSerializer::finalize() { std::string json_contents = json_.dump(); uint32_t json_length = (uint32_t) json_contents.size(); - uint32_t header[] = { GLTF, 2U, 12 + 8 + json_length + padding_for(json_length) + 8 + binary_length + padding_for(binary_length) }; + const int GLB_FILE_HEADER = 12; + const int GLB_JSON_HEADER = 8; + const int GLB_BINARY_CHUNK_HEADER = 8; + + uint32_t header[] = { GLTF, 2U, GLB_FILE_HEADER + GLB_JSON_HEADER + json_length + padding_for(json_length) + + GLB_BINARY_CHUNK_HEADER + binary_length + padding_for(binary_length) }; fstream_.write((const char*)header, sizeof(header)); write_block(fstream_, json_contents.begin(), json_contents.end()); write_header(fstream_, binary_length); { + //First, write the indices buffer into our glb file std::ifstream ifs(IfcUtil::path::from_utf8(tmp_filename1_).c_str(), std::ios::binary); fstream_ << ifs.rdbuf(); } { + //Next, write the vertices buffer into our glb file std::ifstream ifs(IfcUtil::path::from_utf8(tmp_filename2_).c_str(), std::ios::binary); fstream_ << ifs.rdbuf(); } diff --git a/src/serializers/GltfSerializer.h b/src/serializers/GltfSerializer.h index ca8c68303a..7450fa2afb 100644 --- a/src/serializers/GltfSerializer.h +++ b/src/serializers/GltfSerializer.h @@ -36,6 +36,8 @@ private: std::ofstream fstream_, tmp_fstream1_, tmp_fstream2_; std::map materials_, meshes_; json json_, node_array_; + int bufferViewId; + int writeMaterial(const IfcGeom::Material& style); public: From 61a7325bc05c4f2da4346285c80b5cea71dd5eec Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 28 Aug 2023 11:58:17 +0500 Subject: [PATCH 13/81] fill-bg for text instead of the entire symbol by default #3594 Before - https://i.imgur.com/OsQycgW.png After - https://i.imgur.com/rZvXIoT.png --- .../blenderbim/bim/module/drawing/svgwriter.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py index 48783336bd..7021c9bfd2 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py @@ -774,11 +774,14 @@ class SvgWriter: "text-anchor": text_anchor, } - def add_fill_bg(self, element): - element = element.copy() + def add_fill_bg(self, element, copy=True): + if copy: + element = element.copy() if hasattr(element, "xml"): attrib = element.xml.attrib - else: + elif isinstance(element, ET.Element): + attrib = element.attrib + else: # assuming it's svgwrite.base.BaseElement attrib = element.attribs attrib["filter"] = "url(#fill-background)" return element @@ -831,7 +834,12 @@ class SvgWriter: field.attrib["class"] = classes_str if fill_bg: - self.svg.add(self.add_fill_bg(symbol_svg)) + symbol_copied = symbol_svg.copy() + for text_tag in symbol_copied.xml.findall("text"): + self.add_fill_bg(text_tag, copy=False) + # NOTE: in case we'll later need to add fill-bg for the entire symbol: + # self.add_fill_bg(symbol_svg, copy=False) + self.svg.add(symbol_copied) self.svg.add(symbol_svg) return None From b8168ca606cbdd6825f279cff9b36cf76bf3e5a4 Mon Sep 17 00:00:00 2001 From: Christoph Mellueh <=> Date: Mon, 28 Aug 2023 10:43:19 +0200 Subject: [PATCH 14/81] add build to Makefile and use it in bcf-pypi Workflow --- .github/workflows/ci-bcf-pypi.yml | 4 ++-- src/bcf/Makefile | 15 ++++++++++++++- src/bcf/pyproject.toml | 6 +++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-bcf-pypi.yml b/.github/workflows/ci-bcf-pypi.yml index ae0a3a8900..03bff9ab75 100644 --- a/.github/workflows/ci-bcf-pypi.yml +++ b/.github/workflows/ci-bcf-pypi.yml @@ -48,10 +48,10 @@ jobs: run: | pip install build cd src/bcf && - python -m build + make dist - name: Publish a Python distribution to PyPI uses: ortega2247/pypi-upload-action@master with: user: __token__ password: ${{ secrets.PYPI_API_TOKEN }} - packages_dir: src/bcf/dist + packages_dir: src/bcf/dist \ No newline at end of file diff --git a/src/bcf/Makefile b/src/bcf/Makefile index 3a3913b971..e310fd08c1 100644 --- a/src/bcf/Makefile +++ b/src/bcf/Makefile @@ -1,3 +1,9 @@ +VERSION:=`date '+%y%m%d'` +SED:=sed -i +ifeq ($(UNAME_S),Darwin) +SED:=sed -i '' -e +endif + .PHONY: ci ci: tox @@ -12,6 +18,13 @@ models: cd src && xsdata generate -p bcf.v2.model --unnest-classes --kw-only --slots -ds Google bcf/v2/xsd cd src && xsdata generate -p bcf.v3.model --unnest-classes --kw-only --slots -ds Google bcf/v3/xsd +.PHONY: dist +dist: + rm -rf dist + $(SED) "s/999999/$(VERSION)/" pyproject.toml + python -m build + $(SED) "s/$(VERSION)/999999/" pyproject.toml + # .PHONY # api: -# openapi-python-client generate --url https://api.swaggerhub.com/apis/buildingSMART/BCF/3.0 +# openapi-python-client generate --url https://api.swaggerhub.com/apis/buildingSMART/BCF/3.0 \ No newline at end of file diff --git a/src/bcf/pyproject.toml b/src/bcf/pyproject.toml index 7dc6d22176..4d7f1b401b 100644 --- a/src/bcf/pyproject.toml +++ b/src/bcf/pyproject.toml @@ -17,7 +17,7 @@ dependencies = [ "numpy", "ifcopenshell", ] -version = "0.0.1" +version = "0.0.999999" classifiers = [ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Operating System :: OS Independent", @@ -76,7 +76,7 @@ deps = black isort pylint -commands = +commands = black {posargs:.} isort {posargs:.} pylint {posargs:.} --output-format=colorized @@ -138,4 +138,4 @@ max-attributes = 10 [tool.pylint.format] expected-line-ending-format = "LF" -max-line-length = 120 +max-line-length = 120 \ No newline at end of file From 6089d3af780409888f17c2de0d1741890b52f03f Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 28 Aug 2023 16:13:37 +0500 Subject: [PATCH 15/81] shape_builder docs test --- .../ifcopenshell/util/shape_builder.py | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index aef9bca169..e34aa289c7 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -127,13 +127,16 @@ class ShapeBuilder: def rectangle(self, size: Vector = Vector((1.0, 1.0)).freeze(), position: Vector = None): """ - function supports both 2d and 3d rectangle sizes + Generate a rectangle polyline, method supports both 2d and 3d rectangle sizes. + :param size: rectangle size + :param type: Vector + :param size: rectangle position, default to `None`. if `position` not specified zero-vector will be used + :param type: Vector, optional - returns IfcIndexedPolyCurve + :return: IfcIndexedPolyCurve """ - # < IfcIndexedPolyCurve return self.polyline(self.get_rectangle_coords(size, position), closed=True) def circle(self, center: Vector = Vector((0.0, 0.0)).freeze(), radius=1.0): @@ -572,9 +575,17 @@ class ShapeBuilder: disk_solid = self.file.createIfcSweptDiskSolid(Directrix=path_curve, Radius=radius) return disk_solid - def get_representation(self, context, items, representation_type=None): - # > items - could be a list or single curve/IfcExtrudedAreaSolid - # < IfcShapeRepresentation + def get_representation(self, context, items, representation_type:str = None): + """Create IFC representation for the specified context and items. + + :param context: IfcGeometricRepresentationSubContext + :param items: could be a list or single curve/IfcExtrudedAreaSolid + :param representation_type: Explicitly specified RepresentationType, defaults to `None`. + If not provided it will be guessed from the items types. + :type representation_type: str, optional + + :return: IfcRepresentation + """ if not isinstance(items, collections.abc.Iterable): items = [items] From 921d412fc73268ef0c4d6c8a42620afe5e1d761b Mon Sep 17 00:00:00 2001 From: Ryan Schultz Date: Mon, 28 Aug 2023 10:11:24 -0500 Subject: [PATCH 16/81] Spreadsheet Import/Export: Fix feet and inch formatting --- .../ifcopenshell/util/unit.py | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/unit.py b/src/ifcopenshell-python/ifcopenshell/util/unit.py index d9c3c4259b..e3dc8aa6d0 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/unit.py +++ b/src/ifcopenshell-python/ifcopenshell/util/unit.py @@ -574,9 +574,10 @@ def format_length( if imperial_unit == "foot": feet = int(value) inches = (value - feet) * 12 + elif imperial_unit == "inch": - inches = value % 12 - feet = int(round((value - inches) / 12)) + inches = value * 12 + # Round to the nearest 1/N nearest = round(inches * precision) @@ -586,14 +587,22 @@ def format_length( # If fraction is a whole number, format it accordingly if frac.denominator == 1: - if suppress_zero_inches and frac.numerator == 0: - return f"{feet}'" - return f"{feet}' - {frac.numerator}\"" - if frac.numerator > frac.denominator: + if imperial_unit == "inch": + return f"{round(inches)}\"" + if suppress_zero_inches: + if imperial_unit == "foot": + return f"{round(value)}'" + elif not suppress_zero_inches: + if imperial_unit == "foot": + return f"{round(value)}' - 0\"" + if frac.numerator > frac.denominator and not frac.denominator == 0: remainder = frac.numerator % frac.denominator whole = int((frac.numerator - remainder) / frac.denominator) - return f"{feet}' - {whole} {remainder}/{frac.denominator}\"" - return f"{feet}' - {frac.numerator}/{frac.denominator}\"" + if imperial_unit == "foot": + return f"{feet}' - {whole} {remainder}/{frac.denominator}\"" + elif imperial_unit == "inch": + return f"{whole} {remainder}/{frac.denominator}\"" + elif unit_system == "metric": rounded_val = round(value / precision) * precision return f"{rounded_val:.{decimal_places}f}" From 4506eb0df91f152bf7c45b696ba0890092407b1a Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Tue, 29 Aug 2023 00:45:01 +0100 Subject: [PATCH 17/81] fix removing drawings from sheets when deleting drawings #3645 --- .../blenderbim/bim/module/drawing/operator.py | 3 +++ src/blenderbim/blenderbim/tool/drawing.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 9ca530ea86..5f28e663c6 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -1545,6 +1545,9 @@ class RemoveDrawing(bpy.types.Operator, Operator): removed_drawings = [drawing.id() for drawing in drawings] for drawing in drawings: + sheet_references = tool.Drawing.get_sheet_references(drawing) + for reference in sheet_references: + bpy.ops.bim.remove_drawing_from_sheet(reference=reference.id()) core.remove_drawing(tool.Ifc, tool.Drawing, drawing=drawing) diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index aa3af91100..f78862baf9 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -1835,3 +1835,17 @@ class Drawing(blenderbim.core.tool.Drawing): direction = end - start offset = distance * (direction / np.linalg.norm(direction)) return (start - offset).tolist(), (end + offset).tolist() + + @classmethod + def get_sheet_references(cls, drawing): + sheet_references = [] + drawing_reference = cls.get_drawing_document(drawing) + for sheet in tool.Ifc.get().by_type("IfcDocumentInformation"): + if not sheet.Scope == "SHEET": + continue + references = cls.get_document_references(sheet) + for reference in references: + if reference.Location == drawing_reference.Location: + sheet_references.append(reference) + break + return sheet_references From bc9b48237374c24b8810ad91dafa70c6ba5c7f2f Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 29 Aug 2023 10:31:16 +0500 Subject: [PATCH 18/81] Rename IFC AU Library to IFC Furniture library Just thought watching BIM Voice last video that some people may overlook it like something Australia specific with "IFC AU Library" name. --- .../{IFC4 AU Library.ifc => IFC4 Furniture Library.ifc} | 0 src/blenderbim/scripts/generate_furniture_library.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/blenderbim/blenderbim/bim/data/libraries/{IFC4 AU Library.ifc => IFC4 Furniture Library.ifc} (100%) diff --git a/src/blenderbim/blenderbim/bim/data/libraries/IFC4 AU Library.ifc b/src/blenderbim/blenderbim/bim/data/libraries/IFC4 Furniture Library.ifc similarity index 100% rename from src/blenderbim/blenderbim/bim/data/libraries/IFC4 AU Library.ifc rename to src/blenderbim/blenderbim/bim/data/libraries/IFC4 Furniture Library.ifc diff --git a/src/blenderbim/scripts/generate_furniture_library.py b/src/blenderbim/scripts/generate_furniture_library.py index b0bf34c3a1..d18920e900 100644 --- a/src/blenderbim/scripts/generate_furniture_library.py +++ b/src/blenderbim/scripts/generate_furniture_library.py @@ -1877,4 +1877,4 @@ class LibraryGenerator: if __name__ == "__main__": path = Path(__file__).parents[1] / "blenderbim/bim/data/libraries" - LibraryGenerator().generate(output_filename=str(path / "IFC4 AU Library.ifc")) + LibraryGenerator().generate(output_filename=str(path / "IFC4 Furniture Library.ifc")) From 808ff548ec08671d593ea3e956458fa73e78f9e9 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 29 Aug 2023 10:42:33 +0500 Subject: [PATCH 19/81] IfcElementType now appears first in Object Metadata Because it's seems more general workflow to create types than just assign classes. Example - https://i.imgur.com/DD8twX3.png --- src/blenderbim/blenderbim/bim/module/root/data.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/root/data.py b/src/blenderbim/blenderbim/bim/module/root/data.py index 1efb72b543..6b91e18ab8 100644 --- a/src/blenderbim/blenderbim/bim/module/root/data.py +++ b/src/blenderbim/blenderbim/bim/module/root/data.py @@ -49,8 +49,8 @@ class IfcClassData: @classmethod def ifc_products(cls): products = [ - "IfcElement", "IfcElementType", + "IfcElement", "IfcSpatialElement", "IfcSpatialElementType", "IfcGroup", @@ -62,8 +62,8 @@ class IfcClassData: version = tool.Ifc.get_schema() if version == "IFC2X3": products = [ - "IfcElement", "IfcElementType", + "IfcElement", "IfcSpatialStructureElement", "IfcGroup", "IfcStructuralItem", From 5e8e18e3b5fba4c225a381ce1140a1de968b8bf1 Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Tue, 29 Aug 2023 10:29:03 +0100 Subject: [PATCH 20/81] Maintain active status filters override when activating 3D model during drawing worfklows --- src/blenderbim/blenderbim/bim/module/drawing/operator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 5f28e663c6..6a25b87f8c 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -1416,6 +1416,7 @@ class ActivateModel(bpy.types.Operator): if view3d_context: bpy.ops.object.hide_view_clear(view3d_context) + bpy.ops.bim.activate_status_filters() subcontext = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") From 4d98151b62170172941c37d756b9d6603c4197f9 Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:28:40 +0100 Subject: [PATCH 21/81] fix various issues by preventing data from linked IFCs to be saved in current project --- src/blenderbim/blenderbim/bim/export_ifc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/blenderbim/blenderbim/bim/export_ifc.py b/src/blenderbim/blenderbim/bim/export_ifc.py index 5813e8081a..77ed7eaa50 100644 --- a/src/blenderbim/blenderbim/bim/export_ifc.py +++ b/src/blenderbim/blenderbim/bim/export_ifc.py @@ -93,6 +93,8 @@ class IfcExporter: try: if isinstance(obj, bpy.types.Material): continue + if obj.library: + continue tool.Collector.sync(obj) result = self.sync_object_placement(obj) if result: From d1b6c1ffe4c98170e47ce51c1fe559a714c0bcff Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:30:29 +0100 Subject: [PATCH 22/81] fix loading and unloading linked IFCs with a relative path --- src/blenderbim/blenderbim/bim/module/project/operator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index aa1c2309e9..1f924ab63e 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -850,7 +850,7 @@ class UnloadLink(bpy.types.Operator): for scene in bpy.data.scenes: if scene.library and scene.library.filepath == filepath: bpy.data.scenes.remove(scene) - link = context.scene.BIMProjectProperties.links.get(filepath) + link = context.scene.BIMProjectProperties.links.get(self.filepath) link.is_loaded = False return {"FINISHED"} @@ -866,7 +866,7 @@ class LoadLink(bpy.types.Operator): filepath = self.filepath if not os.path.isabs(filepath): filepath = os.path.abspath(os.path.join(bpy.path.abspath("//"), filepath)) - with bpy.data.libraries.load(self.filepath, link=True) as (data_from, data_to): + with bpy.data.libraries.load(filepath, link=True) as (data_from, data_to): data_to.scenes = data_from.scenes for scene in bpy.data.scenes: if not scene.library or scene.library.filepath != filepath: @@ -875,7 +875,7 @@ class LoadLink(bpy.types.Operator): if "IfcProject" not in child.name: continue bpy.data.scenes[0].collection.children.link(child) - link = context.scene.BIMProjectProperties.links.get(filepath) + link = context.scene.BIMProjectProperties.links.get(self.filepath) link.is_loaded = True return {"FINISHED"} From 44431db092af902b79249e84082ba26bd5ff3c24 Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:32:18 +0100 Subject: [PATCH 23/81] fix toggle link selectability and visibility when linked IFCs use a relative path --- .../blenderbim/bim/module/project/operator.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index 1f924ab63e..6c47978d98 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -910,6 +910,9 @@ class ToggleLinkSelectability(bpy.types.Operator): def execute(self, context): props = context.scene.BIMProjectProperties link = props.links.get(self.link) + self.filepath = self.link + if not os.path.isabs(self.filepath): + self.filepath = os.path.abspath(os.path.join(bpy.path.abspath("//"), self.filepath)) for collection in self.get_linked_collections(): collection.hide_select = not collection.hide_select link.is_selectable = not collection.hide_select @@ -917,7 +920,7 @@ class ToggleLinkSelectability(bpy.types.Operator): def get_linked_collections(self): return [ - c for c in bpy.data.collections if "IfcProject" in c.name and c.library and c.library.filepath == self.link + c for c in bpy.data.collections if "IfcProject" in c.name and c.library and c.library.filepath == self.filepath ] @@ -932,6 +935,9 @@ class ToggleLinkVisibility(bpy.types.Operator): def execute(self, context): props = context.scene.BIMProjectProperties link = props.links.get(self.link) + self.filepath = self.link + if not os.path.isabs(self.filepath): + self.filepath = os.path.abspath(os.path.join(bpy.path.abspath("//"), self.filepath)) if self.mode == "WIREFRAME": self.toggle_wireframe(link) elif self.mode == "VISIBLE": @@ -968,7 +974,7 @@ class ToggleLinkVisibility(bpy.types.Operator): def get_linked_collections(self): return [ - c for c in bpy.data.collections if "IfcProject" in c.name and c.library and c.library.filepath == self.link + c for c in bpy.data.collections if "IfcProject" in c.name and c.library and c.library.filepath == self.filepath ] From f23ebc4031522a8d6f4c52dfa3477f43a469cd10 Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Tue, 29 Aug 2023 17:00:24 +0100 Subject: [PATCH 24/81] fix issue where add materials operator would only show when a material is selected --- src/blenderbim/blenderbim/bim/module/material/ui.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/material/ui.py b/src/blenderbim/blenderbim/bim/module/material/ui.py index 5c3b678a88..dc50a8db14 100644 --- a/src/blenderbim/blenderbim/bim/module/material/ui.py +++ b/src/blenderbim/blenderbim/bim/module/material/ui.py @@ -58,6 +58,8 @@ class BIM_PT_materials(Panel): row.alignment = "RIGHT" if self.props.material_type == "IfcMaterial": + if not self.props.active_material_id: + row.operator("bim.add_material", text="", icon="ADD") if self.props.materials and self.props.active_material_index < len(self.props.materials): material = self.props.materials[self.props.active_material_index] if material.ifc_definition_id: @@ -66,13 +68,10 @@ class BIM_PT_materials(Panel): row.operator("bim.disable_editing_material", text="", icon="CANCEL").material = material.ifc_definition_id self.draw_editable_material_attributes_ui() else: - row.operator("bim.add_material", text="", icon="ADD") op = row.operator("bim.select_by_material", text="", icon="RESTRICT_SELECT_OFF") op.material = material.ifc_definition_id row.operator("bim.enable_editing_material", text="", icon="GREASEPENCIL").material = material.ifc_definition_id row.operator("bim.remove_material", text="", icon="X").material = material.ifc_definition_id - else: - row.operator("bim.add_material", text="", icon="ADD") else: row.operator("bim.add_material_set", text="", icon="ADD").set_type = self.props.material_type if self.props.materials and self.props.active_material_index < len(self.props.materials): From 101972fbad53866b5d8bcaab1ae213525fece8bc Mon Sep 17 00:00:00 2001 From: Bruno Postle Date: Tue, 29 Aug 2023 22:28:02 +0100 Subject: [PATCH 25/81] BlenderBIM keep view when switching git revision --- src/blenderbim/blenderbim/tool/ifcgit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/tool/ifcgit.py b/src/blenderbim/blenderbim/tool/ifcgit.py index 33f2fc39e3..6dd445c498 100644 --- a/src/blenderbim/blenderbim/tool/ifcgit.py +++ b/src/blenderbim/blenderbim/tool/ifcgit.py @@ -220,7 +220,7 @@ class IfcGit: bpy.data.orphans_purge(do_recursive=True) - bpy.ops.bim.load_project(filepath=path_ifc) + bpy.ops.bim.load_project(filepath=path_ifc, should_start_fresh_session=False) bpy.ops.object.select_all(action="DESELECT") @classmethod From c520e160312743aa49e0bac514d7c6726528251b Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Wed, 30 Aug 2023 18:15:10 +1000 Subject: [PATCH 26/81] Fix #3644. Annotation matrixes properly calculated now for RCPs. --- .../blenderbim/bim/module/drawing/annotation.py | 17 +++++++++++++---- .../blenderbim/bim/module/drawing/decoration.py | 4 +++- .../blenderbim/bim/module/drawing/svgwriter.py | 2 +- src/blenderbim/blenderbim/tool/drawing.py | 9 +++++++++ src/blenderbim/blenderbim/tool/geometry.py | 4 +++- src/blenderbim/docs/devs/writing_docs.rst | 8 ++++++++ src/ifccsv/ifccsv.py | 2 +- 7 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/annotation.py b/src/blenderbim/blenderbim/bim/module/drawing/annotation.py index 10e1e59e5a..9188291f40 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/annotation.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/annotation.py @@ -16,11 +16,13 @@ # You should have received a copy of the GNU General Public License # along with BlenderBIM Add-on. If not, see . -import bpy import os -import blenderbim.tool as tool -from mathutils import Vector +import bpy +import math import bmesh +import blenderbim.tool as tool +import ifcopenshell.util.element +from mathutils import Vector, Matrix class Annotator: @@ -111,7 +113,7 @@ class Annotator: def get_annotation_obj(drawing, object_type, data_type): camera = tool.Ifc.get_object(drawing) co1, _, _, _ = Annotator.get_placeholder_coords(camera) - matrix_world = camera.matrix_world.copy() + matrix_world = tool.Drawing.get_camera_matrix(camera) matrix_world.translation = co1 collection = camera.BIMObjectProperties.collection @@ -154,6 +156,13 @@ class Annotator: camera = bpy.context.scene.camera z_offset = camera.matrix_world.to_quaternion() @ Vector((0, 0, -1)) + + if ( + ifcopenshell.util.element.get_pset(tool.Ifc.get_entity(camera), "EPset_Drawing", "TargetView") + == "REFLECTED_PLAN_VIEW" + ): + z_offset *= -1 + y = camera.data.ortho_scale / 4 res_x = bpy.context.scene.render.resolution_x diff --git a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py index 13c66efa5f..6b21e95bee 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py @@ -520,7 +520,9 @@ class BaseDecorator: return matrix.inverted()[i].to_3d().normalized() text_dir_world_x_axis = get_basis_vector(obj.matrix_world) - camera_matrix = camera.matrix_world.normalized() + + camera_matrix = tool.Drawing.get_camera_matrix(camera) + text_dir = (camera_matrix.inverted().to_quaternion() @ text_dir_world_x_axis).to_2d().normalized() pos = location_3d_to_region_2d(region, region3d, text_world_position) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py index 7021c9bfd2..a987157c63 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py @@ -805,7 +805,7 @@ class SvgWriter: text_dir_world_x_axis = get_basis_vector(text_obj.matrix_world) # RCP cameras may be scaled, so reset scales. - camera_matrix = self.camera.matrix_world.normalized() + camera_matrix = tool.Drawing.get_camera_matrix(self.camera) text_dir = (camera_matrix.inverted().to_quaternion() @ text_dir_world_x_axis).to_2d().normalized() angle = math.degrees(-text_dir.angle_signed(Vector((1, 0)))) diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index f78862baf9..bcf9c1ebae 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -1849,3 +1849,12 @@ class Drawing(blenderbim.core.tool.Drawing): sheet_references.append(reference) break return sheet_references + + def get_camera_matrix(self, camera): + matrix_world = camera.matrix_world.copy().normalized() + location, rotation, scale = matrix_world.decompose() + if scale.x < 0 or scale.y < 0 or scale.z < 0: + # RCPs may be inversely scaled. We discard the scale and rotate the Z to compensate. + rotate180z = mathutils.Matrix.Rotation(math.radians(180.0), 4, "Z") + return mathutils.Matrix.Translation(location) @ rotation.to_matrix().to_4x4() @ rotate180z + return mathutils.Matrix.Translation(location) @ rotation.to_matrix().to_4x4() diff --git a/src/blenderbim/blenderbim/tool/geometry.py b/src/blenderbim/blenderbim/tool/geometry.py index 3b78dfb8d4..0544c9d330 100644 --- a/src/blenderbim/blenderbim/tool/geometry.py +++ b/src/blenderbim/blenderbim/tool/geometry.py @@ -29,7 +29,7 @@ import blenderbim.core.spatial import blenderbim.tool as tool import blenderbim.bim.import_ifc from math import radians -from mathutils import Vector +from mathutils import Vector, Matrix from blenderbim.bim.ifc import IfcStore @@ -59,6 +59,8 @@ class Geometry(blenderbim.core.tool.Geometry): # Note that clearing scale has no impact on cameras. if (obj.scale - Vector((1.0, 1.0, 1.0))).length > 1e-4: if not obj.data: + location, rotation, _ = obj.matrix_world.decompose() + obj.matrix_world = Matrix.Translation(location) @ rotation.to_matrix().to_4x4() obj.matrix_world.normalize() elif obj.data.users == 1: context_override = {} diff --git a/src/blenderbim/docs/devs/writing_docs.rst b/src/blenderbim/docs/devs/writing_docs.rst index c5be24d5b2..0d14e89bee 100644 --- a/src/blenderbim/docs/devs/writing_docs.rst +++ b/src/blenderbim/docs/devs/writing_docs.rst @@ -60,3 +60,11 @@ download. See also blocks should be used to reference `further reading `__ links. + +Tables can be very annoying to format. You can use a CSV table instead. + +.. csv-table:: + :header: "Foo", "Bar", "Baz" + + "ABC", "01", "02" + "DEF", "03", "04" diff --git a/src/ifccsv/ifccsv.py b/src/ifccsv/ifccsv.py index d8e31a2183..1f72bf6c54 100755 --- a/src/ifccsv/ifccsv.py +++ b/src/ifccsv/ifccsv.py @@ -258,7 +258,7 @@ class IfcCsv: reverse = sort_data["order"] == "DESC" self.results = sorted(self.results, key=lambda x: natural_sort(x[i]), reverse=reverse) else: - if include_global_id and len(list(self.results[0])) > 1: + if include_global_id and len(list(self.results)[0]) > 1: self.results = sorted(self.results, key=lambda x: x[1]) elif not include_global_id: self.results = sorted(self.results, key=lambda x: x[0]) From 26e292dd34a11d4e968992dbad08d4dbdd68a898 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Tue, 29 Aug 2023 09:04:42 +0200 Subject: [PATCH 27/81] docs: fix backslash in cmake command --- .../docs/ifcopenshell/installation.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ifcopenshell-python/docs/ifcopenshell/installation.rst b/src/ifcopenshell-python/docs/ifcopenshell/installation.rst index 33ac16898e..c9942bb038 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell/installation.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell/installation.rst @@ -136,13 +136,13 @@ operating systems. GCC (4.7 or newer) or Clang (any version) is required. -DOCC_INCLUDE_DIR=/usr/include/ \ # Optional Collada support - -DCOLLADA_SUPPORT=On + -DCOLLADA_SUPPORT=On \ -DOPENCOLLADA_INCLUDE_DIR="/usr/local/include/opencollada" \ -DOPENCOLLADA_LIBRARY_DIR="/usr/local/lib/opencollada" \ -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/ \ # Optional HDF5 support - -DHDF5_SUPPORT=On + -DHDF5_SUPPORT=On \ -DHDF5_LIBRARIES="/usr/local/hdf5/lib/libhdf5_cpp.so;/usr/local/hdf5/lib/libhdf5.so;/usr/lib64/libz.so;/usr/lib64/libsz.so;/usr/lib64/libaec.so" \ -DHDF5_INCLUDE_DIR="/usr/local/hdf5/include" \ @@ -190,7 +190,7 @@ GCC (4.7 or newer) or Clang (any version) is required. $ mkdir build && cd build # set library flags $ export LDFLAGS="$LDFLAGS -Wl,-flat_namespace,-undefined,suppress" - $ cmake ../cmake + $ cmake ../cmake \ -DPYTHON_EXECUTABLE=/opt/homebrew/bin/python3.10 \ -DPYTHON_LIBRARY=/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib \ -DPYTHON_INCLUDE_DIR=/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10/ \ @@ -198,10 +198,10 @@ GCC (4.7 or newer) or Clang (any version) is required. -DOCC_INCLUDE_DIR=/opt/homebrew/include/opencascade/ \ -DCGAL_INCLUDE_DIR=/opt/homebrew/include/ \ -DGMP_LIBRARY_DIR=/opt/homebrew/lib/ \ - -DMPFR_LIBRARY_DIR=/opt/homebrew/lib/ + -DMPFR_LIBRARY_DIR=/opt/homebrew/lib/ \ -DHDF5_LIBRARY_DIR=/opt/homebrew/lib/ \ -DHDF5_INCLUDE_DIR=/opt/homebrew/include/ \ - -DCOLLADA_SUPPORT=0 \ + -DCOLLADA_SUPPORT=0 # `sysctl -n hw.ncpu` returns the number of cpu cores on macOS $ make -j$(sysctl -n hw.ncpu) From fbd8ea1edb383ffcd07ab319996e4e27d1790e9c Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 30 Aug 2023 10:57:33 +0200 Subject: [PATCH 28/81] #3660 setSegmentProjection() / --svg-segment-projection options --- src/ifcconvert/IfcConvert.cpp | 3 + src/serializers/SvgSerializer.cpp | 118 ++++++++++++++++-------------- src/serializers/SvgSerializer.h | 76 ++++++++++++++----- 3 files changed, 124 insertions(+), 73 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index fcf7afc7f6..059aebd45c 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -416,6 +416,8 @@ int main(int argc, char** argv) { "Uses the polygonal algorithm for hidden line rendering") ("svg-prefilter", "Prefilter faces and shapes before feeding to HLR algorithm") + ("svg-segment-projection", + "Segment result of projection wrt original products") ("svg-write-poly", "Approximate every curve as polygonal in SVG output") ("svg-project", @@ -1085,6 +1087,7 @@ int main(int argc, char** argv) { static_cast(serializer.get())->setUseNamespace(vmap.count("svg-xmlns") > 0); static_cast(serializer.get())->setUseHlrPoly(vmap.count("svg-poly") > 0); static_cast(serializer.get())->setUsePrefiltering(vmap.count("svg-prefilter") > 0); + static_cast(serializer.get())->setSegmentProjection(vmap.count("svg-segment-projection") > 0); static_cast(serializer.get())->setPolygonal(vmap.count("svg-write-poly") > 0); static_cast(serializer.get())->setAlwaysProject(vmap.count("svg-project") > 0); static_cast(serializer.get())->setWithoutStoreys(vmap.count("svg-without-storeys") > 0); diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index b11db7287c..92a58485a5 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -1149,14 +1149,14 @@ void SvgSerializer::write(const geometry_data& data) { if (storey) { auto it = storey_hlr.find(storey); if (it == storey_hlr.end()) { - it = storey_hlr.insert({ storey, hlr_t(use_prefiltering_, use_hlr_poly_, projection_plane) }).first; + it = storey_hlr.insert({ storey, hlr_t(use_prefiltering_, use_hlr_poly_, segment_projection_, projection_plane) }).first; } - it->second.add(*compound_to_hlr); + it->second.add(*compound_to_hlr, data.product); } else { Logger::Warning("Unable to invoke HLR due to absence of storey containment", data.product); } } else if (hlr) { - hlr->add(*compound_to_hlr); + hlr->add(*compound_to_hlr, data.product); } } } @@ -1699,55 +1699,66 @@ std::array, 3> SvgSerializer::resize() { } void SvgSerializer::draw_hlr(const gp_Pln& pln, const drawing_key& drawing_name) { - TopoDS_Shape hlr_compound_unmirrored = (drawing_name.first ? this->storey_hlr.find(drawing_name.first)->second : *hlr).build(); + auto hlr_items = (drawing_name.first ? this->storey_hlr.find(drawing_name.first)->second : *hlr).build(); - if (!hlr_compound_unmirrored.IsNull()) { - // Compound 3D curves for mirroring to work - ShapeFix_Edge sfe; - TopExp_Explorer exp(hlr_compound_unmirrored, TopAbs_EDGE); - for (; exp.More(); exp.Next()) { - sfe.FixAddCurve3d(TopoDS::Edge(exp.Current())); - } + for (auto& p : hlr_items) { + const TopoDS_Shape& hlr_compound_unmirrored = p.second; - // Mirror to match SVG coord system. - // @todo this is very wasteful. We better do the Y-mirror in the SVG writing and - // not on the TopoDS_Shape input. - - TopoDS_Shape hlr_compound; - if (drawing_name.first == nullptr) { - gp_Trsf trsf_mirror; - if (!mirror_y_) { - trsf_mirror.SetMirror(gp_Ax2(gp::Origin(), gp::DY())); + if (!hlr_compound_unmirrored.IsNull()) { + // Compound 3D curves for mirroring to work + ShapeFix_Edge sfe; + TopExp_Explorer exp(hlr_compound_unmirrored, TopAbs_EDGE); + for (; exp.More(); exp.Next()) { + sfe.FixAddCurve3d(TopoDS::Edge(exp.Current())); } - if (mirror_x_) { - gp_Trsf mirror_x; - mirror_x.SetMirror(gp_Ax2(gp::Origin(), gp::DX())); - trsf_mirror.PreMultiply(mirror_x); + + // Mirror to match SVG coord system. + // @todo this is very wasteful. We better do the Y-mirror in the SVG writing and + // not on the TopoDS_Shape input. + + TopoDS_Shape hlr_compound; + if (drawing_name.first == nullptr) { + gp_Trsf trsf_mirror; + if (!mirror_y_) { + trsf_mirror.SetMirror(gp_Ax2(gp::Origin(), gp::DY())); + } + if (mirror_x_) { + gp_Trsf mirror_x; + mirror_x.SetMirror(gp_Ax2(gp::Origin(), gp::DX())); + trsf_mirror.PreMultiply(mirror_x); + } + BRepBuilderAPI_Transform make_transform_mirror(hlr_compound_unmirrored, trsf_mirror, true); + make_transform_mirror.Build(); + hlr_compound = make_transform_mirror.Shape(); + } else { + // In case of building storey-based floor plan the mirroring has already + // been taken into account before projection. + hlr_compound = hlr_compound_unmirrored; } - BRepBuilderAPI_Transform make_transform_mirror(hlr_compound_unmirrored, trsf_mirror, true); - make_transform_mirror.Build(); - hlr_compound = make_transform_mirror.Shape(); - } else { - // In case of building storey-based floor plan the mirroring has already - // been taken into account before projection. - hlr_compound = hlr_compound_unmirrored; - } - exp.Init(hlr_compound, TopAbs_EDGE); - BRep_Builder B; - path_object* po; - if (drawing_name.first) { - po = &start_path(pln, drawing_name.first, "class=\"projection\""); - } else { - po = &start_path(pln, drawing_name.second, "class=\"projection\""); - } - for (; exp.More(); exp.Next()) { - TopoDS_Wire w; - B.MakeWire(w); - B.Add(w, exp.Current()); - write(*po, w); - } + exp.Init(hlr_compound, TopAbs_EDGE); + BRep_Builder B; + path_object* po; + std::string name; + if (p.first) { + name = nameElement(p.first); + boost::replace_all(name, "class=\"", "class=\"projection "); + } else { + name = "class=\"projection\""; + } + if (drawing_name.first) { + po = &start_path(pln, drawing_name.first, name); + } else { + po = &start_path(pln, drawing_name.second, name); + } + for (; exp.More(); exp.Next()) { + TopoDS_Wire w; + B.MakeWire(w); + B.Add(w, exp.Current()); + write(*po, w); + } + } } } @@ -1812,18 +1823,19 @@ void SvgSerializer::addTextAnnotations(const drawing_key& k) { v.Transform(trsf_view); auto svg_name = nameElement(ann); - path_object* po; - if (k.first) { - po = &start_path(meta.pln_3d, k.first, svg_name); - } else { - po = &start_path(meta.pln_3d, k.second, svg_name); - } if (object_type.size()) { // postfix the object_type for CSS matching boost::replace_all(svg_name, "class=\"IfcAnnotation\"", "class=\"IfcAnnotation " + object_type + "\""); } + path_object* po; + if (k.first) { + po = &start_path(meta.pln_3d, k.first, svg_name); + } else { + po = &start_path(meta.pln_3d, k.second, svg_name); + } + boost::optional font_size; std::vector tokens; boost::split(tokens, name, boost::is_any_of("_")); @@ -1987,7 +1999,7 @@ void SvgSerializer::finalize() { // @todo do we have always have pln here? if (use_hlr && pln) { - hlr = new hlr_t(use_prefiltering_, use_hlr_poly_, *pln); + hlr = new hlr_t(use_prefiltering_, use_hlr_poly_, segment_projection_, *pln); } section_data_ = std::vector{ sd }; diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index 6cd806737c..3a44563ddc 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -205,31 +205,52 @@ namespace { class hlr_calc { private: const HLRAlgo_Projector& projector_; + const std::list>* product_shapes_ = nullptr; public: - typedef TopoDS_Shape result_type; + typedef std::list> result_type; hlr_calc(const HLRAlgo_Projector& projector) : projector_(projector) {} - TopoDS_Shape operator()(boost::blank&) const { + void set_product_shape(const std::list>* product_shapes) { + product_shapes_ = product_shapes; + } + + result_type operator()(boost::blank&) const { throw std::runtime_error(""); } - TopoDS_Shape operator()(opencascade::handle& algo) { + result_type operator()(opencascade::handle& algo) { algo->Projector(projector_); algo->Update(); algo->Hide(); HLRBRep_HLRToShape hlr_shapes(algo); - return occt_join(hlr_shapes.OutLineVCompound(), hlr_shapes.VCompound()); + if (product_shapes_) { + std::list> r; + for (auto& p : *product_shapes_) { + r.push_back({ p.first, occt_join(hlr_shapes.OutLineVCompound(p.second), hlr_shapes.VCompound(p.second)) }); + } + return r; + } else { + return { {nullptr, occt_join(hlr_shapes.OutLineVCompound(), hlr_shapes.VCompound())}}; + } } - TopoDS_Shape operator()(opencascade::handle& algo) { + result_type operator()(opencascade::handle& algo) { algo->Projector(projector_); algo->Update(); HLRBRep_PolyHLRToShape hlr_shapes; hlr_shapes.Update(algo); - return occt_join(hlr_shapes.OutLineVCompound(), hlr_shapes.VCompound()); + if (product_shapes_) { + std::list> r; + for (auto& p : *product_shapes_) { + r.push_back({ p.first, occt_join(hlr_shapes.OutLineVCompound(p.second), hlr_shapes.VCompound(p.second)) }); + } + return r; + } else { + return { {nullptr, occt_join(hlr_shapes.OutLineVCompound(), hlr_shapes.VCompound()) } }; + } } }; @@ -240,13 +261,13 @@ namespace { gp_XYZ dxyz, xdir, ydir; public: - std::list::const_iterator item; + TopoDS_Shape* item; TopoDS_Face face; bool is_convex; // @note copying the BRepTopAdaptor_FClass2d didn't work so it's a pointer BRepTopAdaptor_FClass2d* fclass; - face_info(std::list::const_iterator it, const TopoDS_Face& fa) + face_info(TopoDS_Shape* it, const TopoDS_Face& fa) : item(it) , face(fa) , fclass(nullptr) @@ -334,17 +355,19 @@ namespace { hlr_brep_or_poly_t engine_; bool use_prefiltering_; bool use_hlr_poly_; + bool segment_projection_; gp_Ax1 view_direction_; HLRAlgo_Projector projector_; std::multimap large_ortho_faces_; - std::list items_; + std::list> items_; public: - prefiltered_hlr(bool use_prefiltering, bool use_hlr_poly, const gp_Pln& view_direction) + prefiltered_hlr(bool use_prefiltering, bool use_hlr_poly, bool segment_projection, const gp_Pln& view_direction) : use_prefiltering_(use_prefiltering) , use_hlr_poly_(use_hlr_poly) + , segment_projection_(segment_projection) // @nb negative z in accordance with occt projector convention (and opengl) , view_direction_(view_direction.Axis()) { @@ -359,7 +382,7 @@ namespace { projector_ = HLRAlgo_Projector(trsf, false, 1.); } - bool is_obscured_(std::list::const_iterator sit) { + bool is_obscured_(TopoDS_Shape* sit) { const TopoDS_Shape& s = *sit; double min_d = std::numeric_limits::infinity(); @@ -393,9 +416,9 @@ namespace { return false; } - void add(const TopoDS_Shape& s) { + void add(const TopoDS_Shape& s, const IfcUtil::IfcBaseEntity* product) { if (!use_prefiltering_) { - items_.insert(items_.end(), s); + items_.insert(items_.end(), {product, s}); return; } @@ -434,7 +457,7 @@ namespace { Logger::Notice("Included " + std::to_string(n_faces_included) + " faces out of " + std::to_string(n_total) + " after prefiltering"); - auto it = items_.insert(items_.end(), C); + auto it = items_.insert(items_.end(), { product, C }); { TopExp_Explorer exp(C, TopAbs_FACE); @@ -458,7 +481,7 @@ namespace { auto d = -(pnt.XYZ() - view_direction_.Location().XYZ()).Dot(view_direction_.Direction().XYZ()); if (d > 1.e-5) { - large_ortho_faces_.insert({ d, face_info(it, face) }); + large_ortho_faces_.insert({ d, face_info(&it->second, face) }); } } } @@ -467,15 +490,15 @@ namespace { } } } else { - items_.insert(items_.end(), s); + items_.insert(items_.end(), { product, s }); } } - TopoDS_Shape build() { + std::list> build() { size_t n_included = 0; for (auto it = items_.begin(); it != items_.end(); ++it) { - if (!use_prefiltering_ || !is_obscured_(it)) { - hlr_writer vis(*it); + if (!use_prefiltering_ || !is_obscured_(&it->second)) { + hlr_writer vis(it->second); boost::apply_visitor(vis, engine_); n_included++; } @@ -483,7 +506,11 @@ namespace { if (use_prefiltering_) { Logger::Notice("Included " + std::to_string(n_included) + " elements out of " + std::to_string(items_.size()) + " after prefiltering"); } + hlr_calc vis(projector_); + if (true) { + vis.set_product_shape(&items_); + } return boost::apply_visitor(vis, engine_); } }; @@ -517,7 +544,7 @@ protected: storey_height_display_types storey_height_display_; bool draw_door_arcs_, is_floor_plan_; bool auto_section_, auto_elevation_; - bool use_namespace_, use_hlr_poly_, use_prefiltering_, always_project_, polygonal_; + bool use_namespace_, use_hlr_poly_, use_prefiltering_, segment_projection_, always_project_, polygonal_; bool emit_building_storeys_; bool no_css_; bool unify_inputs_; @@ -570,6 +597,7 @@ public: , use_namespace_(false) , use_hlr_poly_(false) , use_prefiltering_(false) + , segment_projection_(false) , always_project_(false) , polygonal_(false) , emit_building_storeys_(true) @@ -657,6 +685,14 @@ public: return use_prefiltering_; } + void setSegmentProjection(bool b) { + segment_projection_ = b; + } + + bool getSegmentProjection() const { + return segment_projection_; + } + void setPolygonal(bool b) { polygonal_ = b; } From 383038fdb4fd93a745f4ee6753fdfbf2f9c87acc Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 30 Aug 2023 11:38:20 +0200 Subject: [PATCH 29/81] Update ci-py-only.yml --- .github/workflows/ci-py-only.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-py-only.yml b/.github/workflows/ci-py-only.yml index 8591d7b20c..6b13686022 100644 --- a/.github/workflows/ci-py-only.yml +++ b/.github/workflows/ci-py-only.yml @@ -88,6 +88,7 @@ jobs: 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: | From b231f43fc78a06285ae6e1e500dd38efd69736aa Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 30 Aug 2023 11:38:28 +0200 Subject: [PATCH 30/81] Update ci.yml --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5c4e4c58e..06c247f325 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,6 +114,7 @@ jobs: 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 run: | From a2bb015c790a0855a75bef97787e4c0c0249d794 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 30 Aug 2023 13:48:31 +0200 Subject: [PATCH 31/81] Update validate.py - catch some runtime errors --- src/ifcopenshell-python/ifcopenshell/validate.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/validate.py b/src/ifcopenshell-python/ifcopenshell/validate.py index dc2e67d4db..bd1b8cfd66 100644 --- a/src/ifcopenshell-python/ifcopenshell/validate.py +++ b/src/ifcopenshell-python/ifcopenshell/validate.py @@ -323,7 +323,8 @@ def validate(f, logger, express_rules=False): f = ifcopenshell.open(f) else: - raise e + logger.error(f'Unsupported schema: {schema_name}') + return log_internal_cpp_errors(filename, logger) @@ -406,7 +407,15 @@ def validate(f, logger, express_rules=False): ) for attr in entity.all_inverse_attributes(): - val = getattr(inst, attr.name()) + try: + val = getattr(inst, attr.name()) + except Exception as e: + if hasattr(logger, "set_state"): + logger.set_state('attribute', f"{entity.name()}.{attr.name()}") + logger.error(str(e)) + else: + logger.error("For instance:\n %s\n%s", inst, e) + continue try: assert_valid_inverse(attr, val, schema) except ValidationError as e: From 3e45f39ea22b5c0f731f143cf51901a44036d7f4 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 30 Aug 2023 17:43:11 +0500 Subject: [PATCH 32/81] Fixed #3666 after 101972f --- src/blenderbim/blenderbim/tool/drawing.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index bcf9c1ebae..32f1836ae6 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -1849,8 +1849,9 @@ class Drawing(blenderbim.core.tool.Drawing): sheet_references.append(reference) break return sheet_references - - def get_camera_matrix(self, camera): + + @classmethod + def get_camera_matrix(cls, camera): matrix_world = camera.matrix_world.copy().normalized() location, rotation, scale = matrix_world.decompose() if scale.x < 0 or scale.y < 0 or scale.z < 0: From 73d77b8382910183a4f5b329aa92f6fc0d35aa5d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 30 Aug 2023 14:56:35 +0200 Subject: [PATCH 33/81] Update rule_executor.py - catch some runtime errors --- .../ifcopenshell/express/rule_executor.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ifcopenshell-python/ifcopenshell/express/rule_executor.py b/src/ifcopenshell-python/ifcopenshell/express/rule_executor.py index 89c2d3bfa9..d7d20f2122 100644 --- a/src/ifcopenshell-python/ifcopenshell/express/rule_executor.py +++ b/src/ifcopenshell-python/ifcopenshell/express/rule_executor.py @@ -217,7 +217,14 @@ def run(f, logger): check(value[0], S.declaration_by_name(value.is_a()), instance=inst) for inst in f: - values = list(inst) + try: + values = list(inst) + except Exception as e: + if hasattr(logger, "set_state"): + logger.error(str(e)) + else: + logger.error("For instance:\n %s\n%s", inst, e) + continue entity = S.declaration_by_name(inst.is_a()) attrs = entity.all_attributes() for i, (attr, val, is_derived) in enumerate( From ad0c49ac3720b62b39df39cb43b4b4943df3f345 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 31 Aug 2023 12:35:03 +1000 Subject: [PATCH 34/81] Bump IOS to take advantage of setSegmentProjection --- src/blenderbim/Makefile | 2 +- src/ifcopenshell-python/Makefile | 2 +- .../docs/ifcconvert/installation.rst | 10 ++-- .../docs/ifcopenshell-python/installation.rst | 56 +++++++++---------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/blenderbim/Makefile b/src/blenderbim/Makefile index 64f78f0581..1ed65ffd2a 100644 --- a/src/blenderbim/Makefile +++ b/src/blenderbim/Makefile @@ -171,7 +171,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-dadcbe6-$(PLATFORM)64.zip + cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-fdb8ea1-$(PLATFORM)64.zip cd dist/working && unzip ifcopenshell-python* cp -r dist/working/ifcopenshell dist/blenderbim/libs/site/packages/ diff --git a/src/ifcopenshell-python/Makefile b/src/ifcopenshell-python/Makefile index db0d62e3ff..d7efb9bca9 100644 --- a/src/ifcopenshell-python/Makefile +++ b/src/ifcopenshell-python/Makefile @@ -103,7 +103,7 @@ endif mkdir -p dist/ifcopenshell cp -r ifcopenshell/* dist/ifcopenshell/ - cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-dadcbe6-$(PLATFORM)64.zip + cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-fdb8ea1-$(PLATFORM)64.zip cd dist/working && unzip ifcopenshell-python* cp -r dist/working/ifcopenshell/ifcopenshell_wrapper.py dist/ifcopenshell/ ifeq ($(PLATFORM), win) diff --git a/src/ifcopenshell-python/docs/ifcconvert/installation.rst b/src/ifcopenshell-python/docs/ifcconvert/installation.rst index f0f713c1e8..47aac61c69 100644 --- a/src/ifcopenshell-python/docs/ifcconvert/installation.rst +++ b/src/ifcopenshell-python/docs/ifcconvert/installation.rst @@ -20,11 +20,11 @@ Pre-built packages | build-linux64_ | build-win32_ | build-win64_ | build-macos64_ | build-macosm164_ | +----------------+----------------+----------------+----------------+------------------+ -.. _build-linux64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-linux64.zip -.. _build-win32: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-win32.zip -.. _build-win64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-win64.zip -.. _build-macos64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-macos64.zip -.. _build-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-dadcbe6-macosm164.zip +.. _build-linux64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-linux64.zip +.. _build-win32: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-win32.zip +.. _build-win64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-win64.zip +.. _build-macos64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-macos64.zip +.. _build-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-macosm164.zip 2. Unzip the downloaded file and run IfcConvert using the command line. diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst b/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst index 0d7439ff03..fefb482fad 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst @@ -40,34 +40,34 @@ changes in the IfcOpenShell C++ core. | Python 3.11 | py311-linux64_ | py311-win32_ | py311-win64_ | N/A | py311-macosm164_ | +-------------+----------------+----------------+----------------+----------------+------------------+ -.. _py36-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dadcbe6-linux64.zip -.. _py37-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-linux64.zip -.. _py38-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-linux64.zip -.. _py39-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-linux64.zip -.. _py310-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-linux64.zip -.. _py311-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dadcbe6-linux64.zip -.. _py36-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dadcbe6-win32.zip -.. _py37-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-win32.zip -.. _py38-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-win32.zip -.. _py39-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-win32.zip -.. _py310-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-win32.zip -.. _py311-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dadcbe6-win32.zip -.. _py36-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dadcbe6-win64.zip -.. _py37-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-win64.zip -.. _py38-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-win64.zip -.. _py39-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-win64.zip -.. _py310-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-win64.zip -.. _py311-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dadcbe6-win64.zip -.. _py36-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-dadcbe6-macos64.zip -.. _py37-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-macos64.zip -.. _py38-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-macos64.zip -.. _py39-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-macos64.zip -.. _py310-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-macos64.zip -.. _py37-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-dadcbe6-macosm164.zip -.. _py38-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-dadcbe6-macosm164.zip -.. _py39-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-dadcbe6-macosm164.zip -.. _py310-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-dadcbe6-macosm164.zip -.. _py311-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-dadcbe6-macosm164.zip +.. _py36-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-fdb8ea1-linux64.zip +.. _py37-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-linux64.zip +.. _py38-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-linux64.zip +.. _py39-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-linux64.zip +.. _py310-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-linux64.zip +.. _py311-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-fdb8ea1-linux64.zip +.. _py36-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-fdb8ea1-win32.zip +.. _py37-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-win32.zip +.. _py38-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-win32.zip +.. _py39-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-win32.zip +.. _py310-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-win32.zip +.. _py311-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-fdb8ea1-win32.zip +.. _py36-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-fdb8ea1-win64.zip +.. _py37-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-win64.zip +.. _py38-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-win64.zip +.. _py39-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-win64.zip +.. _py310-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-win64.zip +.. _py311-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-fdb8ea1-win64.zip +.. _py36-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-fdb8ea1-macos64.zip +.. _py37-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-macos64.zip +.. _py38-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-macos64.zip +.. _py39-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-macos64.zip +.. _py310-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-macos64.zip +.. _py37-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-macosm164.zip +.. _py38-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-macosm164.zip +.. _py39-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-macosm164.zip +.. _py310-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-macosm164.zip +.. _py311-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-fdb8ea1-macosm164.zip 2. Unzip the downloaded file and copy the ``ifcopenshell`` directory into your Python path. If you're not sure where your Python path is, run the following From adcf22f28199e1d42638b563153a5a31291f95ae Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 31 Aug 2023 12:40:27 +1000 Subject: [PATCH 35/81] Fix #3002. You can now have metadata classes on projection lines. --- .../blenderbim/bim/module/drawing/operator.py | 117 ++++++++++-------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 6a25b87f8c..389d5958fa 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -555,7 +555,7 @@ class CreateDrawing(bpy.types.Operator): if self.camera.data.BIMCameraProperties.calculate_shapely_surfaces: # shapely variant - group = root.findall(".//{http://www.w3.org/2000/svg}g")[0] + group = root.find("{http://www.w3.org/2000/svg}g") nm = group.attrib["{http://www.ifcopenshell.org/ns}name"] m4 = np.array(json.loads(group.attrib["{http://www.ifcopenshell.org/ns}plane"])) m3 = np.array(json.loads(group.attrib["{http://www.ifcopenshell.org/ns}matrix3"])) @@ -566,10 +566,10 @@ class CreateDrawing(bpy.types.Operator): m44[1][3] = m3[1][2] m44 = np.linalg.inv(m44) - projections = group.findall('.//{http://www.w3.org/2000/svg}g[@class="projection"]') or [] + projections = root.xpath(".//svg:g[contains(@class, 'projection')]", namespaces={'svg': 'http://www.w3.org/2000/svg'}) + boundary_lines = [] for projection in projections: - boundary_lines = [] for path in projection.findall("./{http://www.w3.org/2000/svg}path"): # Rounding is necessary to ensure coincident points are coincident start, end = [[round(float(o), 1) for o in co[1:].split(",")] for co in path.attrib["d"].split()] @@ -578,50 +578,57 @@ class CreateDrawing(bpy.types.Operator): # Extension by 0.5mm is necessary to ensure lines overlap with other diagonal lines start, end = tool.Drawing.extend_line(start, end, 0.5) boundary_lines.append(shapely.LineString([start, end])) - unioned_boundaries = shapely.union_all(shapely.GeometryCollection(boundary_lines)) - closed_polygons = shapely.polygonize(unioned_boundaries.geoms) - for polygon in closed_polygons.geoms: - # Less than 1mm2 is not worth styling on sheet - if polygon.area < 1: - continue - centroid = polygon.centroid - internal_point = centroid if polygon.contains(centroid) else polygon.representative_point() - if internal_point: - internal_point = [internal_point.x, internal_point.y] - a, b = self.drawing_to_model_co(m44, m4, internal_point, 0.0), self.drawing_to_model_co( - m44, m4, internal_point, -100.0 - ) - inside_elements = [e for e in tree.select(self.pythonize(a)) if not e.is_a("IfcAnnotation")] - if not inside_elements: - elements = [ - e - for e in tree.select_ray(self.pythonize(a), self.pythonize(b - a)) - if not e.instance.is_a("IfcAnnotation") - and tool.Cad.is_point_on_edge( - Vector(list(e.position)), (Vector(self.pythonize(a)), Vector(self.pythonize(b))) + unioned_boundaries = shapely.union_all(shapely.GeometryCollection(boundary_lines)) + closed_polygons = shapely.polygonize(unioned_boundaries.geoms) + + for polygon in closed_polygons.geoms: + # Less than 1mm2 is not worth styling on sheet + if polygon.area < 1: + continue + centroid = polygon.centroid + internal_point = centroid if polygon.contains(centroid) else polygon.representative_point() + if internal_point: + internal_point = [internal_point.x, internal_point.y] + a, b = self.drawing_to_model_co(m44, m4, internal_point, 0.0), self.drawing_to_model_co( + m44, m4, internal_point, -100.0 + ) + inside_elements = [e for e in tree.select(self.pythonize(a)) if not e.is_a("IfcAnnotation")] + if not inside_elements: + elements = [ + e + for e in tree.select_ray(self.pythonize(a), self.pythonize(b - a)) + if not e.instance.is_a("IfcAnnotation") + and tool.Cad.is_point_on_edge( + Vector(list(e.position)), (Vector(self.pythonize(a)), Vector(self.pythonize(b))) + ) + ] + if elements: + path = etree.Element("path") + d = ( + "M" + + " L".join( + [",".join([str(o) for o in co]) for co in polygon.exterior.coords[0:-1]] ) - ] - if elements: - path = etree.Element("path") - d = ( - "M" - + " L".join( - [",".join([str(o) for o in co]) for co in polygon.exterior.coords[0:-1]] - ) + + " Z" + ) + for interior in polygon.interiors: + d += ( + " M" + + " L".join([",".join([str(o) for o in co]) for co in interior.coords[0:-1]]) + " Z" ) - for interior in polygon.interiors: - d += ( - " M" - + " L".join([",".join([str(o) for o in co]) for co in interior.coords[0:-1]]) - + " Z" - ) - path.attrib["d"] = d - classes = self.get_svg_classes(ifc.by_id(elements[0].instance.id())) - classes.append("surface") - path.set("class", " ".join(list(classes))) - group.insert(0, path) + path.attrib["d"] = d + classes = self.get_svg_classes(ifc.by_id(elements[0].instance.id())) + classes.append(f"intpoint-{internal_point}") + classes.append(f"ab-{a}, {b}") + for i, ray_result in enumerate(elements): + classes.append(f"el{i}-{ray_result.instance.id()}") + classes.append(f"el{i}-pos-{list(ray_result.position)}") + classes.append(f"el{i}-dst-{ray_result.distance}") + classes.append("surface") + path.set("class", " ".join(list(classes))) + group.insert(0, path) if self.camera.data.BIMCameraProperties.calculate_svgfill_surfaces: results = etree.tostring(root).decode("utf8") @@ -636,7 +643,7 @@ class CreateDrawing(bpy.types.Operator): dom1 = parseString(svg_data_1) svg1 = dom1.childNodes[0] - groups1 = [g for g in yield_groups(svg1) if g.getAttribute("class") == "projection"] + groups1 = [g for g in yield_groups(svg1) if "projection" in g.getAttribute("class")] ls_groups = ifcopenshell.ifcopenshell_wrapper.svg_to_line_segments(results, "projection") @@ -854,6 +861,7 @@ class CreateDrawing(bpy.types.Operator): self.serialiser.setSubtractionSettings(ifcopenshell.ifcopenshell_wrapper.ALWAYS) self.serialiser.setUsePrefiltering(True) # See #3359 self.serialiser.setUnifyInputs(True) + self.serialiser.setSegmentProjection(True) if target_view == "REFLECTED_PLAN_VIEW": self.serialiser.setMirrorY(True) # tree = ifcopenshell.geom.tree() @@ -913,7 +921,7 @@ class CreateDrawing(bpy.types.Operator): # Drawing convention states that same objects classes with the same material are merged when cut. join_criteria = ["class", "material.Name", 'r"Pset.*Common"."Status"'] - group = root.findall(".//{http://www.w3.org/2000/svg}g")[0] + group = root.find("{http://www.w3.org/2000/svg}g") joined_paths = {} self.is_manifold_cache = {} @@ -921,9 +929,15 @@ class CreateDrawing(bpy.types.Operator): for el in root.findall(".//{http://www.w3.org/2000/svg}g[@{http://www.ifcopenshell.org/ns}guid]"): element = ifc.by_guid(el.get("{http://www.ifcopenshell.org/ns}guid")) - classes = self.get_svg_classes(element) - classes.append("cut") - el.set("class", " ".join(classes)) + if "projection" in el.get("class", "").split(): + classes = self.get_svg_classes(element) + classes.append("projection") + el.set("class", " ".join(classes)) + continue + else: + classes = self.get_svg_classes(element) + classes.append("cut") + el.set("class", " ".join(classes)) obj = tool.Ifc.get_object(element) if not self.is_manifold(obj): @@ -1045,9 +1059,10 @@ class CreateDrawing(bpy.types.Operator): # IfcConvert puts the projection afterwards which is not correct since # projection should be drawn underneath the cut. group = root.find("{http://www.w3.org/2000/svg}g") - projection = group.find("{http://www.w3.org/2000/svg}g[@class='projection']") - projection.getparent().remove(projection) - group.insert(0, projection) + projections = root.xpath(".//svg:g[contains(@class, 'projection')]", namespaces={'svg': 'http://www.w3.org/2000/svg'}) + for projection in projections: + projection.getparent().remove(projection) + group.insert(0, projection) def generate_annotation(self, context): if not ifcopenshell.util.element.get_pset(self.drawing, "EPset_Drawing", "HasAnnotation"): From 9cc1f5f0e3177e8181dd4a586f61d4aa7b525043 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 31 Aug 2023 08:27:45 +0200 Subject: [PATCH 36/81] #3660 Oops... propagate setting --- src/serializers/SvgSerializer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index 3a44563ddc..9aeff1e0e6 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -508,7 +508,7 @@ namespace { } hlr_calc vis(projector_); - if (true) { + if (segment_projection_) { vis.set_product_shape(&items_); } return boost::apply_visitor(vis, engine_); From b6f2fdef776f3ceae026fe37016d9749a83e29b1 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 31 Aug 2023 18:13:53 +1000 Subject: [PATCH 37/81] Fix #3531. See #3660. Exclude 2D elements from generating shapely surface polygons in drawings. --- src/blenderbim/blenderbim/bim/module/drawing/operator.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 389d5958fa..a158fb0235 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -566,10 +566,19 @@ class CreateDrawing(bpy.types.Operator): m44[1][3] = m3[1][2] m44 = np.linalg.inv(m44) + elements_with_faces = set() + for element in drawing_elements.copy(): + obj = tool.Ifc.get_object(element) + if obj and obj.type == "MESH" and len(obj.data.polygons): + elements_with_faces.add(element.GlobalId) + projections = root.xpath(".//svg:g[contains(@class, 'projection')]", namespaces={'svg': 'http://www.w3.org/2000/svg'}) boundary_lines = [] for projection in projections: + global_id = projection.attrib['{http://www.ifcopenshell.org/ns}guid'] + if global_id not in elements_with_faces: + continue for path in projection.findall("./{http://www.w3.org/2000/svg}path"): # Rounding is necessary to ensure coincident points are coincident start, end = [[round(float(o), 1) for o in co[1:].split(",")] for co in path.attrib["d"].split()] From 10aca77de413396c9dc205b262422d5f72c2b86d Mon Sep 17 00:00:00 2001 From: dushyant basson <39452934+dushyant-basson@users.noreply.github.com> Date: Sat, 12 Aug 2023 02:42:11 +0530 Subject: [PATCH 38/81] Updated to use Qt6; Created initial structure of the viewer with OpenGL widget --- src/qtviewer/CMakeLists.txt | 37 +++++--- src/qtviewer/IfcViewerWidget.cpp | 27 ++++++ src/qtviewer/IfcViewerWidget.h | 23 +++++ src/qtviewer/ParseIfcFile.cpp | 15 ++++ src/qtviewer/ParseIfcFile.h | 15 ++++ src/qtviewer/main.cpp | 22 ++--- src/qtviewer/mainwindow.cpp | 142 +++++++++++++++++-------------- src/qtviewer/mainwindow.h | 40 ++++----- 8 files changed, 205 insertions(+), 116 deletions(-) create mode 100644 src/qtviewer/IfcViewerWidget.cpp create mode 100644 src/qtviewer/IfcViewerWidget.h create mode 100644 src/qtviewer/ParseIfcFile.cpp create mode 100644 src/qtviewer/ParseIfcFile.h diff --git a/src/qtviewer/CMakeLists.txt b/src/qtviewer/CMakeLists.txt index 473013a726..1f4df8ce84 100644 --- a/src/qtviewer/CMakeLists.txt +++ b/src/qtviewer/CMakeLists.txt @@ -20,22 +20,39 @@ cmake_minimum_required(VERSION 3.1.3) message("Running CMakeLists.txt in /src/qtviewer") -message("Provide the path to Qt5 via CMAKE_PREFIX_PATH") -find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +# Specify the Qt version and components to use +set(QT_VERSION 6 CACHE STRING "Qt version") +set(QT_COMPONENTS Core Gui OpenGL OpenGLWidgets Widgets CACHE STRING "Qt components") + +find_package(Qt${QT_VERSION} COMPONENTS ${QT_COMPONENTS} REQUIRED PATHS ${QT_DIR}) + +if(Qt${QT_VERSION}_FOUND) + message(STATUS "Found Qt Version: ${Qt${QT_VERSION}_VERSION}") +endif() add_executable(QtViewer - ../../src/qtviewer/mainwindow.h - ../../src/qtviewer/mainwindow.cpp - ../../src/qtviewer/main.cpp + IfcViewerWidget.h + IfcViewerWidget.cpp + ParseIfcFile.h + ParseIfcFile.cpp + MainWindow.h + MainWindow.cpp + main.cpp ) set_target_properties(QtViewer PROPERTIES - AUTOMOC On + AUTOMOC On + WIN32_EXECUTABLE ON + MACOSX_BUNDLE ON ) target_link_libraries(QtViewer - ${IFCLIBS} - Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets - ${OPENCASCADE_LIBRARIES} -) \ No newline at end of file + ${IFCLIBS} + Qt${QT_VERSION}::Core + Qt${QT_VERSION}::Gui + Qt${QT_VERSION}::OpenGL + Qt${QT_VERSION}::OpenGLWidgets + Qt${QT_VERSION}::Widgets + ${OPENCASCADE_LIBRARIES} +) diff --git a/src/qtviewer/IfcViewerWidget.cpp b/src/qtviewer/IfcViewerWidget.cpp new file mode 100644 index 0000000000..c2a77bed83 --- /dev/null +++ b/src/qtviewer/IfcViewerWidget.cpp @@ -0,0 +1,27 @@ +#include "IfcViewerWidget.h" + +IfcViewerWidget::IfcViewerWidget(QWidget *parent) + : QOpenGLWidget(parent) +{} + +void IfcViewerWidget::initializeGL() +{ + // Set up the rendering context, load shaders and other resources, etc.: + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f); +} + +void IfcViewerWidget::resizeGL(int w, int h) +{ + // Update projection matrix and other size related settings: + m_projection.setToIdentity(); + m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f); +} + +void IfcViewerWidget::paintGL() +{ + // Render geometries from the parsed IFC file + // Draw the scene: + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glClear(GL_COLOR_BUFFER_BIT); +} diff --git a/src/qtviewer/IfcViewerWidget.h b/src/qtviewer/IfcViewerWidget.h new file mode 100644 index 0000000000..8ce7937069 --- /dev/null +++ b/src/qtviewer/IfcViewerWidget.h @@ -0,0 +1,23 @@ +#ifndef IFCVIEWERWIDGET_H +#define IFCVIEWERWIDGET_H + +#include +#include +#include +#include + +class IfcViewerWidget : public QOpenGLWidget +{ +public: + IfcViewerWidget(QWidget *parent = nullptr); + +protected: + void initializeGL() override; + void resizeGL(int w, int h) override; + void paintGL() override; + +private: + QMatrix4x4 m_projection; +}; + +#endif // IFCVIEWERWIDGET_H \ No newline at end of file diff --git a/src/qtviewer/ParseIfcFile.cpp b/src/qtviewer/ParseIfcFile.cpp new file mode 100644 index 0000000000..9a597796d9 --- /dev/null +++ b/src/qtviewer/ParseIfcFile.cpp @@ -0,0 +1,15 @@ +#include "ParseIfcFile.h" + +#include "../ifcparse/Ifc2x3.h" +#define IfcSchema Ifc2x3 + +#include "../ifcgeom/IfcGeom.h" + +ParseIfcFile::ParseIfcFile() {} + +ParseIfcFile::~ParseIfcFile() {} + +void ParseIfcFile::Parse(const std::string& filePath) +{ + //IfcParse::IfcFile ifcFile(filePath); +} \ No newline at end of file diff --git a/src/qtviewer/ParseIfcFile.h b/src/qtviewer/ParseIfcFile.h new file mode 100644 index 0000000000..5c72ed850b --- /dev/null +++ b/src/qtviewer/ParseIfcFile.h @@ -0,0 +1,15 @@ +#ifndef PARSEIFCFILE_H +#define PARSEIFCFILE_H + +#include + +class ParseIfcFile +{ +public: + ParseIfcFile(); + ~ParseIfcFile(); + + void Parse(const std::string& filePath); +}; + +#endif // PARSEIFCFILE_H \ No newline at end of file diff --git a/src/qtviewer/main.cpp b/src/qtviewer/main.cpp index c0171fef3b..b65d413813 100644 --- a/src/qtviewer/main.cpp +++ b/src/qtviewer/main.cpp @@ -1,24 +1,12 @@ - +#include "MainWindow.h" + #include -#include -#ifndef QT_NO_OPENGL -#include -#endif -#include "mainwindow.h" - -int main(int argc, char **argv) +int main(int argc, char *argv[]) { - QApplication app(argc, argv); - - //QGLViewer viewer; - - // Restore the previous viewer state. - //viewer.restoreStateFromFile(); - - MainWindow window; - //window.openFile(" "); + QApplication app(argc, argv); + MainWindow window; window.show(); return app.exec(); diff --git a/src/qtviewer/mainwindow.cpp b/src/qtviewer/mainwindow.cpp index cdc0d18bf3..c666353c82 100644 --- a/src/qtviewer/mainwindow.cpp +++ b/src/qtviewer/mainwindow.cpp @@ -1,97 +1,107 @@ - +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "mainwindow.h" -#include +#include "MainWindow.h" +#include "ParseIfcFile.h" +#include "IfcViewerWidget.h" -#include - -MainWindow::MainWindow() - : QMainWindow() +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) { + this->setWindowTitle("IfcOpenShell Viewer"); + this->resize(800, 600); //temporary reasonable initial size + m_glWidget = new IfcViewerWidget(this); + setCentralWidget(m_glWidget); - IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,true); - IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,false); - IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true); + createActions(); + createMenus(); + createConnections(); +} - - - QMenu *fileMenu = new QMenu(tr("&File"), this); - QAction *openAction = fileMenu->addAction(tr("&Open...")); +void MainWindow::createActions() +{ + openAction = new QAction(tr("&Open"), this); openAction->setShortcut(QKeySequence(tr("Ctrl+O"))); - QAction *quitAction = fileMenu->addAction(tr("E&xit")); - quitAction->setShortcuts(QKeySequence::Quit); - menuBar()->addMenu(fileMenu); + quitAction = new QAction(tr("E&xit"), this); + quitAction->setShortcut(QKeySequence::Quit); - QMenu *viewMenu = new QMenu(tr("&View"), this); - m_backgroundAction = viewMenu->addAction(tr("&Background")); + m_backgroundAction = new QAction(tr("&Background")); m_backgroundAction->setEnabled(false); m_backgroundAction->setCheckable(true); m_backgroundAction->setChecked(false); - //connect(m_backgroundAction, SIGNAL(toggled(bool)), (QWidget*)m_v, SLOT(setViewBackground(bool))); - m_outlineAction = viewMenu->addAction(tr("&Outline")); + m_outlineAction = new QAction(tr("&Outline")); m_outlineAction->setEnabled(false); m_outlineAction->setCheckable(true); - m_outlineAction->setChecked(true); - // connect(m_outlineAction, SIGNAL(toggled(bool)), (QWidget*)m_v, SLOT(setViewOutline(bool))); + m_outlineAction->setChecked(false); +} - menuBar()->addMenu(viewMenu); +void MainWindow::createMenus() +{ + QMenuBar *menuBar = new QMenuBar(); + setMenuBar(menuBar); + fileMenu = new QMenu(tr("&File"), menuBar); + menuBar->addMenu(fileMenu); + + fileMenu->addAction(openAction); + fileMenu->addAction(quitAction); + + viewMenu = new QMenu(tr("&View"), menuBar); + menuBar->addMenu(viewMenu); + + viewMenu->addAction(m_backgroundAction); + viewMenu->addAction(m_outlineAction); +} + +void MainWindow::createConnections() +{ connect(openAction, SIGNAL(triggered()), this, SLOT(openFile())); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); - - //setCentralWidget((QWidget*)m_v); - setWindowTitle(tr("IfcOpenShell QT Viewer")); + //connect(m_backgroundAction, SIGNAL(toggled(bool)), (QWidget*)m_v, SLOT(setViewBackground(bool))); + //connect(m_outlineAction, SIGNAL(toggled(bool)), (QWidget*)m_v, SLOT(setViewOutline(bool))); } -void MainWindow::openFile(const QString &path) +void MainWindow::openFile() { - QString fileName; - if (path.isNull()) - fileName = QFileDialog::getOpenFileName(this, tr("Open IFC"), - m_currentPath, "IFC files (*.ifc)"); - else - fileName = path; + QString filePath = QFileDialog::getOpenFileName(this, tr("Open IFC File"), + ".", tr("IFC Files (*.ifc)")); - if (!fileName.isEmpty()) { - QFile file(fileName); - if (!file.exists()) { - QMessageBox::critical(this, tr("Open IFC"), - QString("Could not open file '%1'.").arg(fileName)); + QFileInfo fileInfo(filePath); + QString fileName = fileInfo.fileName(); - m_outlineAction->setEnabled(false); - m_backgroundAction->setEnabled(false); - return; - } - std::stringstream ss; - if ( ! IfcGeomObjects::Init(fileName.toStdString(),&std::cout,&ss) ) { - QMessageBox::critical(this, tr("Open IFC"), - QString("[Error] unable to parse file '%1'. Or no geometrical entities found" ).arg(fileName)); - return; - } + if (fileName.isEmpty()) + return; - //connect((QWidget*)m_view, SIGNAL(drawNeeded()), this, SLOT(drawIfcObject())); + // Check if the file is a Qt resource file + if (fileName.startsWith(":/")) + return; - if (!fileName.startsWith(":/")) { - m_currentPath = fileName; - setWindowTitle(tr("%1 - IFCViewer").arg(m_currentPath)); - } + QFile file(filePath); + if (!file.exists()) { + QMessageBox::critical(this, tr("Open IFC"), + QString("Could not open '%1'.").arg(filePath)); - m_outlineAction->setEnabled(true); - m_backgroundAction->setEnabled(true); - -// resize(m_view->sizeHint() + QSize(80, 80 + menuBar()->height())); + m_outlineAction->setEnabled(false); + m_backgroundAction->setEnabled(false); + return; } -} + ParseIfcFile parser; + parser.Parse(filePath.toStdString()); -void MainWindow::draw() -{ - - - -} - + m_currentPath = filePath; + setWindowTitle(tr("%1 - IFCViewer").arg(fileName)); + m_outlineAction->setEnabled(true); + m_backgroundAction->setEnabled(true); +} \ No newline at end of file diff --git a/src/qtviewer/mainwindow.h b/src/qtviewer/mainwindow.h index a62e823815..bee337be3a 100644 --- a/src/qtviewer/mainwindow.h +++ b/src/qtviewer/mainwindow.h @@ -1,39 +1,32 @@ - - -#ifndef MAINWINDOW_H +#ifndef MAINWINDOW_H #define MAINWINDOW_H -#include +#include #include #include -#include "../ifcgeom/IfcGeomObjects.h" - -class ObjectsView; - -class QGLViewer; - -QT_BEGIN_NAMESPACE -class QAction; -class QGraphicsView; -class QGraphicsScene; -class QGraphicsRectItem; -QT_END_NAMESPACE +#include +#include class MainWindow : public QMainWindow { Q_OBJECT public: - MainWindow(); - - -public Q_SLOTS: - void draw(); + MainWindow(QWidget *parent = nullptr); public slots: - void openFile(const QString &path = QString()); + void openFile(); private: + void createActions(); + void createMenus(); + void createConnections(); +private: + QMenu *fileMenu; + QAction *openAction; + QAction *quitAction; + + QMenu *viewMenu; QAction *m_nativeAction; QAction *m_glAction; QAction *m_imageAction; @@ -42,6 +35,7 @@ private: QAction *m_outlineAction; QString m_currentPath; + QOpenGLWidget *m_glWidget; }; -#endif +#endif // MAINWINDOW_H From 0380c286a50bde3fd053aab02c30f02350bd3264 Mon Sep 17 00:00:00 2001 From: dushyant basson <39452934+dushyant-basson@users.noreply.github.com> Date: Mon, 14 Aug 2023 13:50:13 +0530 Subject: [PATCH 39/81] Rename files - fixing case change --- src/qtviewer/{mainwindow.cpp => MainWindow.cpp} | 0 src/qtviewer/{mainwindow.h => MainWindow.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/qtviewer/{mainwindow.cpp => MainWindow.cpp} (100%) rename src/qtviewer/{mainwindow.h => MainWindow.h} (100%) diff --git a/src/qtviewer/mainwindow.cpp b/src/qtviewer/MainWindow.cpp similarity index 100% rename from src/qtviewer/mainwindow.cpp rename to src/qtviewer/MainWindow.cpp diff --git a/src/qtviewer/mainwindow.h b/src/qtviewer/MainWindow.h similarity index 100% rename from src/qtviewer/mainwindow.h rename to src/qtviewer/MainWindow.h From 26dd850ac1c60fb0f823681468a157edef925289 Mon Sep 17 00:00:00 2001 From: dushyant basson <39452934+dushyant-basson@users.noreply.github.com> Date: Mon, 14 Aug 2023 14:23:03 +0530 Subject: [PATCH 40/81] added .cache to .gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 247d590e6f..d89b81bfaa 100644 --- a/.gitignore +++ b/.gitignore @@ -96,5 +96,8 @@ src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py # apple .DS_Store +# clangd cache +.cache + # Brickschema -src/blenderbim/blenderbim/bim/schema/Brick.ttl \ No newline at end of file +src/blenderbim/blenderbim/bim/schema/Brick.ttl From 9c4c42e27e74a62b18e3baff0d8f2d1df574e405 Mon Sep 17 00:00:00 2001 From: Dushyant Basson Date: Tue, 29 Aug 2023 09:10:02 +0530 Subject: [PATCH 41/81] comment edit: Qt5 to Qt6 --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 39cdf8bf07..f0ed33b0bc 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -82,7 +82,7 @@ if(NO_WARN) endif() endif() -# QtViewer requires Qt5 +# QtViewer requires Qt6 OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) include(GNUInstallDirs) if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND (NOT BUILD_IFCGEOM)) From 25ce3b039efaa1aa6a65091d3880aee360f8e1ad Mon Sep 17 00:00:00 2001 From: Dushyant Basson Date: Tue, 29 Aug 2023 09:16:02 +0530 Subject: [PATCH 42/81] added IFCOS libraries; Qt include dir --- src/qtviewer/CMakeLists.txt | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/qtviewer/CMakeLists.txt b/src/qtviewer/CMakeLists.txt index 1f4df8ce84..bce0fbcedf 100644 --- a/src/qtviewer/CMakeLists.txt +++ b/src/qtviewer/CMakeLists.txt @@ -31,7 +31,9 @@ if(Qt${QT_VERSION}_FOUND) message(STATUS "Found Qt Version: ${Qt${QT_VERSION}_VERSION}") endif() -add_executable(QtViewer +set(targetName "QtViewer") + +add_executable(${targetName} IfcViewerWidget.h IfcViewerWidget.cpp ParseIfcFile.h @@ -41,14 +43,14 @@ add_executable(QtViewer main.cpp ) -set_target_properties(QtViewer PROPERTIES +set_target_properties(${targetName} PROPERTIES AUTOMOC On WIN32_EXECUTABLE ON MACOSX_BUNDLE ON ) -target_link_libraries(QtViewer - ${IFCLIBS} +target_link_libraries(${targetName} + ${IFCOPENSHELL_LIBRARIES} Qt${QT_VERSION}::Core Qt${QT_VERSION}::Gui Qt${QT_VERSION}::OpenGL @@ -56,3 +58,10 @@ target_link_libraries(QtViewer Qt${QT_VERSION}::Widgets ${OPENCASCADE_LIBRARIES} ) + +target_include_directories(${targetName} PUBLIC + ${QT_DIR}/include +) + +get_target_property(targetIncludeDirs ${targetName} INCLUDE_DIRECTORIES) +message(STATUS "target_include_directories: ${targetIncludeDirs}") \ No newline at end of file From 7687d5e26e6cc9b70d953d5d6cd93074cbeb079a Mon Sep 17 00:00:00 2001 From: Dushyant Basson Date: Tue, 29 Aug 2023 09:48:27 +0530 Subject: [PATCH 43/81] Added output panel (for debug info, etc.) --- src/qtviewer/MainWindow.cpp | 28 ++++++++++++++++++++++++---- src/qtviewer/MainWindow.h | 8 ++++++++ src/qtviewer/ParseIfcFile.cpp | 33 ++++++++++++++++++++++++++++++++- src/qtviewer/ParseIfcFile.h | 12 +++++++++++- 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/qtviewer/MainWindow.cpp b/src/qtviewer/MainWindow.cpp index c666353c82..d7f1189a10 100644 --- a/src/qtviewer/MainWindow.cpp +++ b/src/qtviewer/MainWindow.cpp @@ -6,10 +6,10 @@ #include #include #include +#include #include #include "MainWindow.h" -#include "ParseIfcFile.h" #include "IfcViewerWidget.h" MainWindow::MainWindow(QWidget *parent) @@ -19,7 +19,18 @@ MainWindow::MainWindow(QWidget *parent) this->resize(800, 600); //temporary reasonable initial size m_glWidget = new IfcViewerWidget(this); - setCentralWidget(m_glWidget); + QSizePolicy glSizePolicy = m_glWidget->sizePolicy(); + glSizePolicy.setVerticalStretch(3); + m_glWidget->setSizePolicy(glSizePolicy); + + m_outputText = new QPlainTextEdit(this); + m_outputText->setReadOnly(true); + + QSplitter* splitter = new QSplitter(Qt::Vertical, this); + splitter->addWidget(m_glWidget); + splitter->addWidget(m_outputText); + + setCentralWidget(splitter); createActions(); createMenus(); @@ -69,6 +80,13 @@ void MainWindow::createConnections() connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); //connect(m_backgroundAction, SIGNAL(toggled(bool)), (QWidget*)m_v, SLOT(setViewBackground(bool))); //connect(m_outlineAction, SIGNAL(toggled(bool)), (QWidget*)m_v, SLOT(setViewOutline(bool))); + + connect(&m_parser, &ParseIfcFile::parsingInfo, this, &MainWindow::appendToOutputText); +} + +void MainWindow::appendToOutputText(const QString& message) +{ + m_outputText->appendPlainText(message); } void MainWindow::openFile() @@ -96,8 +114,10 @@ void MainWindow::openFile() return; } - ParseIfcFile parser; - parser.Parse(filePath.toStdString()); + QString message = tr("Opening file: %1\n").arg(filePath); + appendToOutputText(message); + + m_parser.Parse(filePath.toStdString()); m_currentPath = filePath; setWindowTitle(tr("%1 - IFCViewer").arg(fileName)); diff --git a/src/qtviewer/MainWindow.h b/src/qtviewer/MainWindow.h index bee337be3a..2cd41e1ca2 100644 --- a/src/qtviewer/MainWindow.h +++ b/src/qtviewer/MainWindow.h @@ -6,6 +6,9 @@ #include #include #include +#include + +#include "ParseIfcFile.h" class MainWindow : public QMainWindow { @@ -21,6 +24,7 @@ private: void createActions(); void createMenus(); void createConnections(); + void appendToOutputText(const QString& message); private: QMenu *fileMenu; QAction *openAction; @@ -35,7 +39,11 @@ private: QAction *m_outlineAction; QString m_currentPath; + QOpenGLWidget *m_glWidget; + QPlainTextEdit *m_outputText; + + ParseIfcFile m_parser; }; #endif // MAINWINDOW_H diff --git a/src/qtviewer/ParseIfcFile.cpp b/src/qtviewer/ParseIfcFile.cpp index 9a597796d9..b2df481af0 100644 --- a/src/qtviewer/ParseIfcFile.cpp +++ b/src/qtviewer/ParseIfcFile.cpp @@ -4,12 +4,43 @@ #define IfcSchema Ifc2x3 #include "../ifcgeom/IfcGeom.h" +#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" ParseIfcFile::ParseIfcFile() {} ParseIfcFile::~ParseIfcFile() {} +void ParseIfcFile::outputMsg(const std::string& msg) +{ + emit parsingInfo(QString::fromStdString(msg)); +} + void ParseIfcFile::Parse(const std::string& filePath) { - //IfcParse::IfcFile ifcFile(filePath); + IfcParse::IfcFile file(filePath); + + IfcGeom::IteratorSettings settings; + settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true); + settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false); + + IfcGeom::Iterator* it = new IfcGeom::Iterator(settings, &file); + if (!it->initialize()) { + outputMsg("Error: Iterator failed to initialize! Aborting."); + delete it; + return; + } + + do { + //const IfcGeom::BRepElement* bRepElem = it->get_native(); + const IfcGeom::TriangulationElement* triElem = static_cast(it->get()); + outputMsg(triElem->type() + ": " + triElem->name()); + + const boost::shared_ptr& triElemGeom = triElem->geometry_pointer(); + + // materials + const std::vector& elemMats = triElemGeom->materials(); + for (auto mat : elemMats) { + outputMsg(" " + mat.original_name()); + } + } while (it->next()); } \ No newline at end of file diff --git a/src/qtviewer/ParseIfcFile.h b/src/qtviewer/ParseIfcFile.h index 5c72ed850b..2d1a7c5eb0 100644 --- a/src/qtviewer/ParseIfcFile.h +++ b/src/qtviewer/ParseIfcFile.h @@ -1,10 +1,20 @@ #ifndef PARSEIFCFILE_H #define PARSEIFCFILE_H +#include +#include #include -class ParseIfcFile +class ParseIfcFile : public QObject { + Q_OBJECT + +signals: + void parsingInfo(const QString& info); + +private: + void outputMsg(const std::string& msg); + public: ParseIfcFile(); ~ParseIfcFile(); From 84e9e2396a029dd66c9b11a2779f360fa988b169 Mon Sep 17 00:00:00 2001 From: dushyant basson <39452934+dushyant-basson@users.noreply.github.com> Date: Thu, 31 Aug 2023 00:48:17 +0530 Subject: [PATCH 44/81] Updated included header files --- src/qtviewer/ParseIfcFile.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/qtviewer/ParseIfcFile.cpp b/src/qtviewer/ParseIfcFile.cpp index b2df481af0..e541b5d155 100644 --- a/src/qtviewer/ParseIfcFile.cpp +++ b/src/qtviewer/ParseIfcFile.cpp @@ -1,9 +1,5 @@ #include "ParseIfcFile.h" -#include "../ifcparse/Ifc2x3.h" -#define IfcSchema Ifc2x3 - -#include "../ifcgeom/IfcGeom.h" #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" ParseIfcFile::ParseIfcFile() {} @@ -43,4 +39,4 @@ void ParseIfcFile::Parse(const std::string& filePath) outputMsg(" " + mat.original_name()); } } while (it->next()); -} \ No newline at end of file +} From 5c2b7404d28ff633f3aa61eece4352aeb06ecc0f Mon Sep 17 00:00:00 2001 From: dushyant basson <39452934+dushyant-basson@users.noreply.github.com> Date: Thu, 31 Aug 2023 00:52:09 +0530 Subject: [PATCH 45/81] Revert "Updated included header files" This reverts commit 65f86d929ee9cea8ab5dd6ab8e18a12e9d676628. --- src/qtviewer/ParseIfcFile.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qtviewer/ParseIfcFile.cpp b/src/qtviewer/ParseIfcFile.cpp index e541b5d155..b2df481af0 100644 --- a/src/qtviewer/ParseIfcFile.cpp +++ b/src/qtviewer/ParseIfcFile.cpp @@ -1,5 +1,9 @@ #include "ParseIfcFile.h" +#include "../ifcparse/Ifc2x3.h" +#define IfcSchema Ifc2x3 + +#include "../ifcgeom/IfcGeom.h" #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" ParseIfcFile::ParseIfcFile() {} @@ -39,4 +43,4 @@ void ParseIfcFile::Parse(const std::string& filePath) outputMsg(" " + mat.original_name()); } } while (it->next()); -} +} \ No newline at end of file From be785a878cff2de78da556225063e19e9fdadb23 Mon Sep 17 00:00:00 2001 From: dushyant basson <39452934+dushyant-basson@users.noreply.github.com> Date: Thu, 31 Aug 2023 00:52:57 +0530 Subject: [PATCH 46/81] Update src/qtviewer/ParseIfcFile.cpp Co-authored-by: Thomas Krijnen --- src/qtviewer/ParseIfcFile.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/qtviewer/ParseIfcFile.cpp b/src/qtviewer/ParseIfcFile.cpp index b2df481af0..c95f9a7cd9 100644 --- a/src/qtviewer/ParseIfcFile.cpp +++ b/src/qtviewer/ParseIfcFile.cpp @@ -1,8 +1,5 @@ #include "ParseIfcFile.h" -#include "../ifcparse/Ifc2x3.h" -#define IfcSchema Ifc2x3 - #include "../ifcgeom/IfcGeom.h" #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" From 504a116ebf505302518caeb21f936a4d951722a7 Mon Sep 17 00:00:00 2001 From: dushyant basson <39452934+dushyant-basson@users.noreply.github.com> Date: Thu, 31 Aug 2023 00:53:18 +0530 Subject: [PATCH 47/81] Update src/qtviewer/ParseIfcFile.cpp Co-authored-by: Thomas Krijnen --- src/qtviewer/ParseIfcFile.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qtviewer/ParseIfcFile.cpp b/src/qtviewer/ParseIfcFile.cpp index c95f9a7cd9..e5dc8e99bf 100644 --- a/src/qtviewer/ParseIfcFile.cpp +++ b/src/qtviewer/ParseIfcFile.cpp @@ -1,6 +1,5 @@ #include "ParseIfcFile.h" -#include "../ifcgeom/IfcGeom.h" #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" ParseIfcFile::ParseIfcFile() {} From 01b6d9043224c4e8bc4a9c1422bec1fb520d17bf Mon Sep 17 00:00:00 2001 From: "Sigma Dimensions (Yass)" <79010126+myoualid@users.noreply.github.com> Date: Thu, 31 Aug 2023 11:14:53 +0100 Subject: [PATCH 48/81] fix failed context for hotkey Shitf+C #3676 --- src/blenderbim/blenderbim/bim/module/model/workspace.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index ba0ac78390..998de01b1b 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -568,7 +568,8 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): if not bpy.context.selected_objects: return if self.active_material_usage == "LAYER2": - bpy.ops.bim.align_wall(align_type="CENTERLINE") + if bpy.ops.bim.align_wall.poll(): + bpy.ops.bim.align_wall(align_type="CENTERLINE") else: bpy.ops.bim.align_product(align_type="CENTERLINE") From c6b82bfa56d219bd5ac687c1cf3891a7add72b1a Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 31 Aug 2023 22:28:18 +1000 Subject: [PATCH 49/81] Fix #3647. Fix bug where Windows .exe suffix needed to be explicit in commands. No more eval, and commands must now be provided in json form, and variables should be given as simple strings. --- .../blenderbim/bim/module/drawing/operator.py | 58 +++++++++---------- src/blenderbim/blenderbim/bim/ui.py | 10 ++-- src/blenderbim/blenderbim/tool/drawing.py | 9 ++- 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index a158fb0235..1a05c5cefc 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -70,15 +70,6 @@ class profile: print(self.task, timer() - self.start) -def open_with_user_command(user_command, path): - if user_command: - commands = eval(user_command) - for command in commands: - subprocess.Popen(command) - else: - webbrowser.open("file://" + path) - - class Operator: def execute(self, context): IfcStore.execute_ifc_operator(self, context) @@ -269,7 +260,7 @@ class CreateDrawing(bpy.types.Operator): with profile("Combine SVG layers"): svg_path = self.combine_svgs(context, underlay_svg, linework_svg, annotation_svg) - 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) @@ -572,11 +563,13 @@ class CreateDrawing(bpy.types.Operator): if obj and obj.type == "MESH" and len(obj.data.polygons): elements_with_faces.add(element.GlobalId) - projections = root.xpath(".//svg:g[contains(@class, 'projection')]", namespaces={'svg': 'http://www.w3.org/2000/svg'}) + projections = root.xpath( + ".//svg:g[contains(@class, 'projection')]", namespaces={"svg": "http://www.w3.org/2000/svg"} + ) boundary_lines = [] for projection in projections: - global_id = projection.attrib['{http://www.ifcopenshell.org/ns}guid'] + global_id = projection.attrib["{http://www.ifcopenshell.org/ns}guid"] if global_id not in elements_with_faces: continue for path in projection.findall("./{http://www.w3.org/2000/svg}path"): @@ -616,9 +609,7 @@ class CreateDrawing(bpy.types.Operator): path = etree.Element("path") d = ( "M" - + " L".join( - [",".join([str(o) for o in co]) for co in polygon.exterior.coords[0:-1]] - ) + + " L".join([",".join([str(o) for o in co]) for co in polygon.exterior.coords[0:-1]]) + " Z" ) for interior in polygon.interiors: @@ -1068,7 +1059,9 @@ class CreateDrawing(bpy.types.Operator): # IfcConvert puts the projection afterwards which is not correct since # projection should be drawn underneath the cut. group = root.find("{http://www.w3.org/2000/svg}g") - projections = root.xpath(".//svg:g[contains(@class, 'projection')]", namespaces={'svg': 'http://www.w3.org/2000/svg'}) + projections = root.xpath( + ".//svg:g[contains(@class, 'projection')]", namespaces={"svg": "http://www.w3.org/2000/svg"} + ) for projection in projections: projection.getparent().remove(projection) group.insert(0, projection) @@ -1285,11 +1278,15 @@ class CreateSheets(bpy.types.Operator, Operator): # These variables will be made available to the evaluated commands svg = references["SHEET"] - basename = os.path.basename(svg) - path = os.path.dirname(svg) pdf = os.path.splitext(svg)[0] + ".pdf" - eps = os.path.splitext(svg)[0] + ".eps" - dxf = os.path.splitext(svg)[0] + ".dxf" + replacements = { + "svg": svg, + "basename": os.path.basename(svg), + "path": os.path.dirname(svg), + "pdf": pdf, + "eps": os.path.splitext(svg)[0] + ".eps", + "dxf": os.path.splitext(svg)[0] + ".dxf", + } has_sheet_reference = False for reference in tool.Drawing.get_document_references(sheet): @@ -1322,22 +1319,23 @@ class CreateSheets(bpy.types.Operator, Operator): if svg2pdf_command: # With great power comes great responsibility. Example: - # [['inkscape', svg, '-o', pdf]] - commands = eval(svg2pdf_command) + # [["inkscape", "svg", "-o", "pdf"]] + commands = json.loads(svg2pdf_command) for command in commands: - subprocess.run(command) + subprocess.run([replacements.get(c, c) for c in command]) if svg2dxf_command: # With great power comes great responsibility. Example: - # [['inkscape', svg, '-o', eps], ['pstoedit', '-dt', '-f', 'dxf:-polyaslines -mm', eps, dxf, '-psarg', '-dNOSAFER']] - commands = eval(svg2dxf_command) + # [["inkscape", "svg", "-o", "eps"], ["pstoedit", "-dt", "-f", "dxf:-polyaslines -mm", "eps", "dxf", "-psarg", "-dNOSAFER"]] + commands = json.loads(svg2dxf_command) for command in commands: - subprocess.run(command) + command[0] = shutil.which(command[0]) or command[0] + subprocess.run([replacements.get(c, c) for c in command]) if svg2pdf_command: - open_with_user_command(context.preferences.addons["blenderbim"].preferences.pdf_command, pdf) + tool.Drawing.open_with_user_command(context.preferences.addons["blenderbim"].preferences.pdf_command, pdf) else: - open_with_user_command(context.preferences.addons["blenderbim"].preferences.svg_command, svg) + tool.Drawing.open_with_user_command(context.preferences.addons["blenderbim"].preferences.svg_command, svg) class SelectAllDrawings(bpy.types.Operator): @@ -1404,7 +1402,9 @@ class OpenDrawing(bpy.types.Operator): return {"CANCELLED"} for drawing_uri in drawing_uris: - open_with_user_command(context.preferences.addons["blenderbim"].preferences.svg_command, drawing_uri) + tool.Drawing.open_with_user_command( + context.preferences.addons["blenderbim"].preferences.svg_command, drawing_uri + ) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/ui.py b/src/blenderbim/blenderbim/bim/ui.py index 706a3b8163..33112cbb8f 100644 --- a/src/blenderbim/blenderbim/bim/ui.py +++ b/src/blenderbim/blenderbim/bim/ui.py @@ -126,14 +126,14 @@ class BIM_UL_topics(bpy.types.UIList): class BIM_ADDON_preferences(bpy.types.AddonPreferences): bl_idname = "blenderbim" - svg2pdf_command: StringProperty(name="SVG to PDF Command", description="E.g. [['inkscape', svg, '-o', pdf]]") + svg2pdf_command: StringProperty(name="SVG to PDF Command", description='E.g. [["inkscape", "svg", "-o", pdf]]') svg2dxf_command: StringProperty( name="SVG to DXF Command", - description="E.g. [['inkscape', svg, '-o', eps], ['pstoedit', '-dt', '-f', 'dxf:-polyaslines -mm', eps, dxf, '-psarg', '-dNOSAFER']]", + description='E.g. [["inkscape", "svg", "-o", "eps"], ["pstoedit", "-dt", "-f", "dxf:-polyaslines -mm", "eps", "dxf", "-psarg", "-dNOSAFER"]]', ) - svg_command: StringProperty(name="SVG Command", description="E.g. [['firefox', path]]") - pdf_command: StringProperty(name="PDF Command", description="E.g. [['firefox', path]]") - spreadsheet_command: StringProperty(name="Spreadsheet Command", description="E.g. [['libreoffice', path]]") + svg_command: StringProperty(name="SVG Command", description='E.g. [["firefox", "path"]]') + pdf_command: StringProperty(name="PDF Command", description='E.g. [["firefox", "path"]]') + spreadsheet_command: StringProperty(name="Spreadsheet Command", description='E.g. [["libreoffice", "path"]]') openlca_port: IntProperty(name="OpenLCA IPC Port", default=8080) should_hide_empty_props: BoolProperty(name="Should Hide Empty Properties", default=True) should_setup_workspace: BoolProperty(name="Should Setup Workspace Layout for BIM", default=True) diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index 32f1836ae6..36b99fb044 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -20,6 +20,7 @@ import os import re import bpy import math +import json import lark import bmesh import shutil @@ -835,9 +836,11 @@ class Drawing(blenderbim.core.tool.Drawing): @classmethod def open_with_user_command(cls, user_command, path): if user_command: - commands = eval(user_command) + commands = json.loads(user_command) + replacements = {"path": path} for command in commands: - subprocess.Popen(command) + command[0] = shutil.which(command[0]) or command[0] + subprocess.Popen([replacements.get(c, c) for c in command]) else: webbrowser.open("file://" + path) @@ -1849,7 +1852,7 @@ class Drawing(blenderbim.core.tool.Drawing): sheet_references.append(reference) break return sheet_references - + @classmethod def get_camera_matrix(cls, camera): matrix_world = camera.matrix_world.copy().normalized() From 951026a95cd682f5a773e161fccb3e86868c6774 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 31 Aug 2023 22:36:10 +1000 Subject: [PATCH 50/81] Fix #3667. Allow removing drawings if the sheet hasn't yet been generated or manually removed. --- src/blenderbim/blenderbim/bim/module/drawing/sheeter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py b/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py index e309bf0997..f452bcc158 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py @@ -174,6 +174,8 @@ class SheetBuilder: ET.register_namespace("", "http://www.w3.org/2000/svg") layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") + if not os.path.exists(layout_path): + return layout_tree = ET.parse(layout_path) layout_root = layout_tree.getroot() From 1d040a170e5349b17fcc79e7a86b88b6bd0462c7 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 31 Aug 2023 23:04:44 +1000 Subject: [PATCH 51/81] Fix #3649. Increase profile threshold. --- src/blenderbim/blenderbim/bim/module/drawing/operator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 1a05c5cefc..1285187b40 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -847,7 +847,7 @@ class CreateDrawing(bpy.types.Operator): self.serialiser.setPolygonal(True) self.serialiser.setUseHlrPoly(True) # Objects with more than these edges are rendered as wireframe instead of HLR for optimisation - self.serialiser.setProfileThreshold(1000) + self.serialiser.setProfileThreshold(10000) self.serialiser.setUseNamespace(True) self.serialiser.setAlwaysProject(True) self.serialiser.setAutoElevation(False) From 4716c0b7b727d330469d3308a6d41dc32a3ce846 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 1 Sep 2023 16:46:49 +1000 Subject: [PATCH 52/81] IfcTester now supports much more granular statistic reports and more detailed / beautiful HTML reports. --- src/ifctester/ifctester/ids.py | 2 + src/ifctester/ifctester/reporter.py | 99 +++++-- src/ifctester/ifctester/templates/report.html | 256 ++++++++---------- 3 files changed, 201 insertions(+), 156 deletions(-) diff --git a/src/ifctester/ifctester/ids.py b/src/ifctester/ifctester/ids.py index 692d35254c..38f0fc3f95 100644 --- a/src/ifctester/ifctester/ids.py +++ b/src/ifctester/ifctester/ids.py @@ -168,6 +168,8 @@ class Specification: def parse(self, ids_dict): self.name = ids_dict.get("@name", "") + self.description = ids_dict.get("@description", "") + self.instructions = ids_dict.get("@instructions", "") self.minOccurs = ids_dict["@minOccurs"] self.maxOccurs = ids_dict["@maxOccurs"] self.ifcVersion = ids_dict["@ifcVersion"] diff --git a/src/ifctester/ifctester/reporter.py b/src/ifctester/ifctester/reporter.py index ee9e952269..4060198977 100644 --- a/src/ifctester/ifctester/reporter.py +++ b/src/ifctester/ifctester/reporter.py @@ -159,31 +159,85 @@ class Json(Reporter): def report(self): self.results["title"] = self.ids.info.get("title", "Untitled IDS") + self.results["date"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + total_specifications = 0 + total_specifications_pass = 0 + total_requirements = 0 + total_requirements_pass = 0 + total_checks = 0 + total_checks_pass = 0 + status = True self.results["specifications"] = [] for specification in self.ids.specifications: - self.results["specifications"].append(self.report_specification(specification)) + specification_report = self.report_specification(specification) + self.results["specifications"].append(specification_report) + total_specifications += 1 + total_specifications_pass += 1 if specification_report["status"] else 0 + total_requirements += len(specification_report["requirements"]) + total_requirements_pass += len([r for r in specification_report["requirements"] if r["status"]]) + total_checks += specification_report["total_checks"] + total_checks_pass += specification_report["total_checks_pass"] + if not specification_report["status"]: + status = False + self.results["status"] = status + self.results["total_specifications"] = total_specifications + self.results["total_specifications_pass"] = total_specifications_pass + self.results["total_specifications_fail"] = total_specifications - total_specifications_pass + self.results["percent_specifications_pass"] = ( + math.floor((total_specifications_pass / total_specifications) * 100) if total_specifications else "N/A" + ) + self.results["total_requirements"] = total_requirements + self.results["total_requirements_pass"] = total_requirements_pass + self.results["total_requirements_fail"] = total_requirements - total_requirements_pass + self.results["percent_requirements_pass"] = ( + math.floor((total_requirements_pass / total_requirements) * 100) if total_requirements else "N/A" + ) + self.results["total_checks"] = total_checks + self.results["total_checks_pass"] = total_checks_pass + self.results["total_checks_fail"] = total_checks - total_checks_pass + self.results["percent_checks_pass"] = ( + math.floor((total_checks_pass / total_checks) * 100) if total_checks else "N/A" + ) return self.results def report_specification(self, specification): applicability = [a.to_string("applicability") for a in specification.applicability] + total_applicable = len(specification.applicable_entities) + total_checks = 0 + total_checks_pass = 0 requirements = [] for requirement in specification.requirements: + total_fail = len(requirement.failed_entities) + total_checks += total_applicable + total_checks_pass += total_applicable - total_fail requirements.append( { "description": requirement.to_string("requirement"), "status": requirement.status, "failed_entities": self.report_failed_entities(requirement), + "total_applicable": total_applicable, + "total_pass": total_applicable - total_fail, + "total_fail": total_fail, } ) - total = len(specification.applicable_entities) - total_successes = total - len(specification.failed_entities) - percentage = math.floor((total_successes / total) * 100) if total else "N/A" + total_applicable_pass = total_applicable - len(specification.failed_entities) + percent_applicable_pass = ( + math.floor((total_applicable_pass / total_applicable) * 100) if total_applicable else "N/A" + ) + percent_checks_pass = math.floor((total_checks_pass / total_checks) * 100) if total_checks else "N/A" return { "name": specification.name, + "description": specification.description, + "instructions": specification.instructions, "status": specification.status, - "total_successes": total_successes, - "total": total, - "percentage": percentage, + "total_applicable": total_applicable, + "total_applicable_pass": total_applicable_pass, + "total_applicable_fail": total_applicable - total_applicable_pass, + "percent_applicable_pass": percent_applicable_pass, + "total_checks": total_checks, + "total_checks_pass": total_checks_pass, + "total_checks_fail": total_checks - total_checks_pass, + "percent_checks_pass": percent_checks_pass, "required": specification.minOccurs != 0, "applicability": applicability, "requirements": requirements, @@ -223,12 +277,15 @@ class Html(Json): self.results = {} def report(self): - self.results["title"] = self.ids.info.get("title", "Untitled IDS") - self.results["time"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - self.results["specifications"] = [] - for specification in self.ids.specifications: - self.results["specifications"].append(self.report_specification(specification)) - return self.results + super().report() + entity_limit = 100 + for spec in self.results["specifications"]: + for requirement in spec["requirements"]: + total = len(requirement["failed_entities"]) + requirement["failed_entities"] = requirement["failed_entities"][0:entity_limit] + requirement["has_omitted"] = total > entity_limit + requirement["total_entities"] = total + requirement["total_omitted"] = total - entity_limit def to_string(self): import pystache @@ -272,7 +329,7 @@ class Ods(Json): table = Table(name=self.results["title"]) tr = TableRow() - for header in ["Specification", "Status", "Total Compliant", "Total Applicable", "Percentage Compliant"]: + for header in ["Specification", "Status", "Total Pass", "Total Checks", "Percentage Pass"]: tc = TableCell(valuetype="string", stylename="h") tc.addElement(P(text=header)) tr.addElement(tc) @@ -284,9 +341,9 @@ class Ods(Json): [ specification["name"], "Pass" if specification["status"] else "Fail", - str(specification["total_successes"]), - str(specification["total"]), - str(specification["percentage"]), + str(specification["total_checks_pass"]), + str(specification["total_checks"]), + str(specification["percent_checks_pass"]), ] ) @@ -309,7 +366,7 @@ class Ods(Json): continue table = Table(name=specification["name"]) tr = TableRow() - for header in ["Requirement", "Problem", "Element"]: + for header in ["Requirement", "Problem", "Class", "PredefinedType", "Name", "Description", "GlobalId", "Tag", "Element"]: tc = TableCell(valuetype="string", stylename="h") tc.addElement(P(text=header)) tr.addElement(tc) @@ -321,6 +378,12 @@ class Ods(Json): row = [ requirement["description"], failure.get("reason", "No reason provided"), + failure["class"], + failure["predefined_type"], + failure["name"], + failure["description"], + failure["global_id"], + failure["tag"], str(failure.get("element", "No element found")), ] tr = TableRow() diff --git a/src/ifctester/ifctester/templates/report.html b/src/ifctester/ifctester/templates/report.html index e452837ba4..8ab743e1ae 100644 --- a/src/ifctester/ifctester/templates/report.html +++ b/src/ifctester/ifctester/templates/report.html @@ -26,173 +26,153 @@ {{name}}

{{title}}

-

{{time}}

+

{{date}}

+

Summary

+
+
{{percent_checks_pass}}%
+
+

+ {{#status}}Pass{{/status}}{{^status}}Fail{{/status}} + + Specifications passed: {{total_specifications_pass}} / {{total_specifications}} + + + Requirements passed: {{total_requirements_pass}} / {{total_requirements}} + + + Checks passed: {{total_checks_pass}} / {{total_checks}} + +

+
{{#specifications}}

{{name}}

+ {{#description}} +

{{description}}

+ {{/description}} + {{#instructions}} +

{{instructions}}

+ {{/instructions}} +
-
{{percentage}}%
+
{{percent_checks_pass}}%
-
- -

- {{#status}}Pass{{/status}}{{^status}}Fail{{/status}} - Passed: {{total_successes}} / {{total}} ({{percentage}}%) - click here to see details -

-
-
    - {{#requirements}} -
  1. - {{description}} - {{^status}}{{#total}} -

    - {{#failed_entities}} - {{reason}} {{element}}
    - {{/failed_entities}} -

    - {{/total}}{{/status}} -
  2. - {{/requirements}} -
-
+

+ {{#status}}Pass{{/status}}{{^status}}Fail{{/status}} + + Checks passed: {{total_checks_pass}} / {{total_checks}} + + + Elements passed: {{total_applicable_pass}} / {{total_applicable}} + +

+

+ Applicability +

+
    + {{#applicability}} +
  • {{.}}
  • + {{/applicability}} +
+

+ Requirements +

+
    + {{#requirements}} +
  1. +
    + + {{description}} + + {{#total_fail}} + + + + + + + + + + + + + + {{#failed_entities}} + + + + + + + + + + {{/failed_entities}} + {{#has_omitted}} + + + + {{/has_omitted}} + +
    ClassPredefinedTypeNameDescriptionWarningGlobalIdTag
    {{class}}{{predefined_type}}{{name}}{{description}}{{reason}}{{global_id}}{{tag}}
    ... {{total_omitted}} more elements not shown out of {{total_entities}} total ...
    + {{/total_fail}} +
    +
  2. + {{/requirements}} +
{{/specifications}}
From a6bff09c7897ce0745ca3c8eb3bd5fa4f5ba8b1a Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 1 Sep 2023 16:47:55 +1000 Subject: [PATCH 53/81] Update BBIM tester module UI to be compatible with new IfcTester upgrades --- .../blenderbim/bim/module/tester/data.py | 45 +++++++++++++++++++ .../blenderbim/bim/module/tester/operator.py | 43 +++++++++--------- .../blenderbim/bim/module/tester/prop.py | 10 ++--- .../blenderbim/bim/module/tester/ui.py | 42 +++++++---------- src/blenderbim/blenderbim/tool/__init__.py | 1 + 5 files changed, 89 insertions(+), 52 deletions(-) create mode 100644 src/blenderbim/blenderbim/bim/module/tester/data.py diff --git a/src/blenderbim/blenderbim/bim/module/tester/data.py b/src/blenderbim/blenderbim/bim/module/tester/data.py new file mode 100644 index 0000000000..742b471f89 --- /dev/null +++ b/src/blenderbim/blenderbim/bim/module/tester/data.py @@ -0,0 +1,45 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2023 Dion Moult +# +# 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 . + +import bpy +import blenderbim.tool as tool + + +def refresh(): + TesterData.is_loaded = False + + +class TesterData: + data = {} + is_loaded = False + + @classmethod + def load(cls): + cls.data = {"has_report": cls.has_report(), "specification": cls.specification()} + cls.is_loaded = True + + @classmethod + def has_report(cls): + return tool.Tester.report + + @classmethod + def specification(cls): + if not tool.Tester.report: + return {} + props = bpy.context.scene.IfcTesterProperties + return tool.Tester.report[props.active_specification_index] diff --git a/src/blenderbim/blenderbim/bim/module/tester/operator.py b/src/blenderbim/blenderbim/bim/module/tester/operator.py index 0164f0a11d..71150627dc 100644 --- a/src/blenderbim/blenderbim/bim/module/tester/operator.py +++ b/src/blenderbim/blenderbim/bim/module/tester/operator.py @@ -21,15 +21,16 @@ import bpy import time import tempfile import webbrowser -import json import ifctester import ifctester.ids import ifctester.reporter import ifcopenshell import blenderbim.tool as tool +import blenderbim.bim.handler +from blenderbim.bim.module.tester.data import TesterData -class ExecuteIfcTester(bpy.types.Operator): +class ExecuteIfcTester(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.execute_ifc_tester" bl_label = "Execute IfcTester" @@ -54,28 +55,27 @@ class ExecuteIfcTester(bpy.types.Operator): print("Finished loading:", time.time() - start) start = time.time() specs.validate(ifc) - + print("Finished validating:", time.time() - start) start = time.time() if props.generate_html_report: engine = ifctester.reporter.Html(specs) - engine.report() + engine.report() engine.to_file(output) webbrowser.open("file://" + output) - + report = None - report = ifctester.reporter.Json(specs).report()['specifications'] + report = ifctester.reporter.Json(specs).report()["specifications"] if report: - props.has_report = True - props.report = json.dumps(report) + tool.Tester.report = report props.specifications.clear() - c=0 for spec in report: new_spec = props.specifications.add() - new_spec.name = spec['name'] - new_spec.status = spec['status'] + new_spec.name = spec["name"] + new_spec.status = spec["status"] + blenderbim.bim.handler.refresh_ui_data() return {"FINISHED"} @@ -118,23 +118,24 @@ class SelectRequirement(bpy.types.Operator): bl_label = "Select Specification" bl_options = {"REGISTER", "UNDO"} spec_index: bpy.props.IntProperty() - req_index: bpy.props.IntProperty() + req_index: bpy.props.IntProperty() def execute(self, context): props = context.scene.IfcTesterProperties - report = json.loads(props.report) + report = tool.Tester.report props.old_index = self.spec_index - failed_entities = report[self.spec_index]['requirements'] [self.req_index]['failed_entities'] + failed_entities = report[self.spec_index]["requirements"][self.req_index]["failed_entities"] props.n_entities = len(failed_entities) props.has_entities = True if props.n_entities > 0 else False props.failed_entities.clear() for e in failed_entities: - new_entity = props.failed_entities.add() - new_entity.element = e['element'] - new_entity.reason = e['reason'] + new_entity = props.failed_entities.add() + new_entity.element = e["element"] + new_entity.reason = e["reason"] return {"FINISHED"} + class SelectEntity(bpy.types.Operator): bl_idname = "bim.select_entity" bl_label = "Select Entity" @@ -142,13 +143,14 @@ class SelectEntity(bpy.types.Operator): ifc_id: bpy.props.IntProperty() def execute(self, context): - bpy.ops.object.select_all(action='DESELECT') + bpy.ops.object.select_all(action="DESELECT") for obj in context.scene.objects: if obj.BIMObjectProperties.ifc_definition_id == self.ifc_id: obj.select_set(True) bpy.context.view_layer.objects.active = obj return {"FINISHED"} - + + class ExportBcf(bpy.types.Operator): bl_idname = "bim.export_bcf" bl_label = "Export BCF" @@ -168,7 +170,6 @@ class ExportBcf(bpy.types.Operator): bcf_reporter.report() bcf_reporter.to_file(output) print("Finished exporting!") - self.report({"INFO"}, 'Finished exporting!') + self.report({"INFO"}, "Finished exporting!") return {"FINISHED"} - diff --git a/src/blenderbim/blenderbim/bim/module/tester/prop.py b/src/blenderbim/blenderbim/bim/module/tester/prop.py index 63637301a3..b68600f053 100644 --- a/src/blenderbim/blenderbim/bim/module/tester/prop.py +++ b/src/blenderbim/blenderbim/bim/module/tester/prop.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with BlenderBIM Add-on. If not, see . +from blenderbim.bim.module.tester.data import TesterData from blenderbim.bim.prop import StrProperty from bpy.types import PropertyGroup from bpy.props import ( @@ -34,8 +35,8 @@ def purge(): pass -def get_failure_entities(): - return +def update_active_specification_index(self, context): + TesterData.load() class Specification(PropertyGroup): @@ -53,13 +54,10 @@ class IfcTesterProperties(PropertyGroup): ifc_file: StringProperty(default="", name="IFC File") should_load_from_memory: BoolProperty(default=False, name="Load from Memory") generate_html_report: BoolProperty(default=False, name="Generate HTML report") - active_specification_index: IntProperty(name="Active Specification Index") - active_requirement_index: IntProperty(name="Active Requirement Index") + active_specification_index: IntProperty(name="Active Specification Index", update=update_active_specification_index) old_index: IntProperty(name="", default=0) active_failed_entity_index: IntProperty(name="Active Failed Entity Index") - report: StringProperty(default="", name="JSON report") specifications: CollectionProperty(name="Specifications", type=Specification) failed_entities: CollectionProperty(name="FailedEntities", type=FailedEntities) - has_report: BoolProperty(default=False, name="") has_entities: BoolProperty(default=False, name="") n_entities: IntProperty(name="", default=0) diff --git a/src/blenderbim/blenderbim/bim/module/tester/ui.py b/src/blenderbim/blenderbim/bim/module/tester/ui.py index 3db173884e..2af3f7af98 100644 --- a/src/blenderbim/blenderbim/bim/module/tester/ui.py +++ b/src/blenderbim/blenderbim/bim/module/tester/ui.py @@ -18,7 +18,7 @@ import blenderbim.tool as tool from bpy.types import Panel, UIList -import json +from blenderbim.bim.module.tester.data import TesterData class BIM_PT_tester(Panel): @@ -31,6 +31,9 @@ class BIM_PT_tester(Panel): bl_parent_id = "BIM_PT_tab_quality_control" def draw(self, context): + if not TesterData.is_loaded: + TesterData.load() + self.layout.use_property_split = True props = context.scene.IfcTesterProperties @@ -53,7 +56,7 @@ class BIM_PT_tester(Panel): row = self.layout.row() row.operator("bim.execute_ifc_tester") - if props.has_report: + if TesterData.data["has_report"]: self.layout.template_list( "BIM_UL_tester_specifications", "", @@ -69,33 +72,26 @@ class BIM_PT_tester(Panel): def draw_editable_ui(self, context): props = context.scene.IfcTesterProperties - i = props.active_specification_index - dic_report = json.loads(props.report) + specification = TesterData.data["specification"] - total_successes = dic_report[i]["total_successes"] - total = dic_report[i]["total"] - percentage = dic_report[i]["percentage"] - n_requirements = len(dic_report[i]["requirements"]) + n_requirements = len(specification["requirements"]) row = self.layout.row() - row.label(text=f"Passed: {total_successes}/{total} ({percentage}%)") + row.label( + text=f'Passed: {specification["total_checks_pass"]}/{specification["total_checks"]} ({specification["percent_checks_pass"]}%)' + ) row = self.layout.row() row.label(text=f"Requirements ({n_requirements}):") - c = 0 box = self.layout.box() - for req in dic_report[i]["requirements"]: + for i, requirement in enumerate(specification["requirements"]): row = box.row(align=True) - row.label(text=f" {c+1}. {req['description']}") - if req["status"]: - row.label(text="PASS", icon="CHECKMARK") - else: - row.label(text="FAIL", icon="CANCEL") + row.label(text=requirement["description"], icon="CHECKMARK" if requirement["status"] else "CANCEL") + if not requirement["status"]: op = row.operator("bim.select_requirement", text="", icon="LONGDISPLAY") - op.spec_index = i - op.req_index = c - c += 1 + op.spec_index = props.active_specification_index + op.req_index = i - if props.old_index == i and props.n_entities > 0: + if props.old_index == props.active_specification_index and props.n_entities > 0: row = self.layout.row() row.label(text=f"Failed entities [{props.n_entities}]:") self.layout.template_list( @@ -112,11 +108,7 @@ class BIM_UL_tester_specifications(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.name, icon="WORDWRAP_ON") - if item.status: - row.label(text="PASS") - else: - row.label(text="FAIL") + row.label(text=item.name, icon="CHECKMARK" if item.status else "CANCEL") class BIM_UL_tester_failed_entities(UIList): diff --git a/src/blenderbim/blenderbim/tool/__init__.py b/src/blenderbim/blenderbim/tool/__init__.py index 118f61a047..54f5e9ea57 100644 --- a/src/blenderbim/blenderbim/tool/__init__.py +++ b/src/blenderbim/blenderbim/tool/__init__.py @@ -51,6 +51,7 @@ from blenderbim.tool.structural import Structural from blenderbim.tool.style import Style from blenderbim.tool.surveyor import Surveyor from blenderbim.tool.system import System +from blenderbim.tool.tester import Tester from blenderbim.tool.type import Type from blenderbim.tool.unit import Unit from blenderbim.tool.search import Search From b087d5125f4710f65f934fcb0aa60894960ce971 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 1 Sep 2023 16:55:18 +1000 Subject: [PATCH 54/81] Bump IOS --- src/blenderbim/Makefile | 2 +- src/ifcopenshell-python/Makefile | 2 +- .../docs/ifcconvert/installation.rst | 10 ++-- .../docs/ifcopenshell-python/installation.rst | 56 +++++++++---------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/blenderbim/Makefile b/src/blenderbim/Makefile index 1ed65ffd2a..b5b39c73ed 100644 --- a/src/blenderbim/Makefile +++ b/src/blenderbim/Makefile @@ -171,7 +171,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-fdb8ea1-$(PLATFORM)64.zip + cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-9cc1f5f-$(PLATFORM)64.zip cd dist/working && unzip ifcopenshell-python* cp -r dist/working/ifcopenshell dist/blenderbim/libs/site/packages/ diff --git a/src/ifcopenshell-python/Makefile b/src/ifcopenshell-python/Makefile index d7efb9bca9..9c47c7ae68 100644 --- a/src/ifcopenshell-python/Makefile +++ b/src/ifcopenshell-python/Makefile @@ -103,7 +103,7 @@ endif mkdir -p dist/ifcopenshell cp -r ifcopenshell/* dist/ifcopenshell/ - cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-fdb8ea1-$(PLATFORM)64.zip + cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-9cc1f5f-$(PLATFORM)64.zip cd dist/working && unzip ifcopenshell-python* cp -r dist/working/ifcopenshell/ifcopenshell_wrapper.py dist/ifcopenshell/ ifeq ($(PLATFORM), win) diff --git a/src/ifcopenshell-python/docs/ifcconvert/installation.rst b/src/ifcopenshell-python/docs/ifcconvert/installation.rst index 47aac61c69..da8fecf14d 100644 --- a/src/ifcopenshell-python/docs/ifcconvert/installation.rst +++ b/src/ifcopenshell-python/docs/ifcconvert/installation.rst @@ -20,11 +20,11 @@ Pre-built packages | build-linux64_ | build-win32_ | build-win64_ | build-macos64_ | build-macosm164_ | +----------------+----------------+----------------+----------------+------------------+ -.. _build-linux64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-linux64.zip -.. _build-win32: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-win32.zip -.. _build-win64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-win64.zip -.. _build-macos64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-macos64.zip -.. _build-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-fdb8ea1-macosm164.zip +.. _build-linux64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-9cc1f5f-linux64.zip +.. _build-win32: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-9cc1f5f-win32.zip +.. _build-win64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-9cc1f5f-win64.zip +.. _build-macos64: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-9cc1f5f-macos64.zip +.. _build-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.7.0-9cc1f5f-macosm164.zip 2. Unzip the downloaded file and run IfcConvert using the command line. diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst b/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst index fefb482fad..5c0d1b045a 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell-python/installation.rst @@ -40,34 +40,34 @@ changes in the IfcOpenShell C++ core. | Python 3.11 | py311-linux64_ | py311-win32_ | py311-win64_ | N/A | py311-macosm164_ | +-------------+----------------+----------------+----------------+----------------+------------------+ -.. _py36-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-fdb8ea1-linux64.zip -.. _py37-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-linux64.zip -.. _py38-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-linux64.zip -.. _py39-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-linux64.zip -.. _py310-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-linux64.zip -.. _py311-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-fdb8ea1-linux64.zip -.. _py36-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-fdb8ea1-win32.zip -.. _py37-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-win32.zip -.. _py38-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-win32.zip -.. _py39-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-win32.zip -.. _py310-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-win32.zip -.. _py311-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-fdb8ea1-win32.zip -.. _py36-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-fdb8ea1-win64.zip -.. _py37-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-win64.zip -.. _py38-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-win64.zip -.. _py39-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-win64.zip -.. _py310-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-win64.zip -.. _py311-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-fdb8ea1-win64.zip -.. _py36-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-fdb8ea1-macos64.zip -.. _py37-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-macos64.zip -.. _py38-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-macos64.zip -.. _py39-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-macos64.zip -.. _py310-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-macos64.zip -.. _py37-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-fdb8ea1-macosm164.zip -.. _py38-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-fdb8ea1-macosm164.zip -.. _py39-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-fdb8ea1-macosm164.zip -.. _py310-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-fdb8ea1-macosm164.zip -.. _py311-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-fdb8ea1-macosm164.zip +.. _py36-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-9cc1f5f-linux64.zip +.. _py37-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-9cc1f5f-linux64.zip +.. _py38-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-9cc1f5f-linux64.zip +.. _py39-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-9cc1f5f-linux64.zip +.. _py310-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-9cc1f5f-linux64.zip +.. _py311-linux64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-9cc1f5f-linux64.zip +.. _py36-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-9cc1f5f-win32.zip +.. _py37-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-9cc1f5f-win32.zip +.. _py38-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-9cc1f5f-win32.zip +.. _py39-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-9cc1f5f-win32.zip +.. _py310-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-9cc1f5f-win32.zip +.. _py311-win32: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-9cc1f5f-win32.zip +.. _py36-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-9cc1f5f-win64.zip +.. _py37-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-9cc1f5f-win64.zip +.. _py38-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-9cc1f5f-win64.zip +.. _py39-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-9cc1f5f-win64.zip +.. _py310-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-9cc1f5f-win64.zip +.. _py311-win64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-9cc1f5f-win64.zip +.. _py36-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-36-v0.7.0-9cc1f5f-macos64.zip +.. _py37-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-9cc1f5f-macos64.zip +.. _py38-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-9cc1f5f-macos64.zip +.. _py39-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-9cc1f5f-macos64.zip +.. _py310-macos64: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-9cc1f5f-macos64.zip +.. _py37-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-37-v0.7.0-9cc1f5f-macosm164.zip +.. _py38-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-38-v0.7.0-9cc1f5f-macosm164.zip +.. _py39-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-39-v0.7.0-9cc1f5f-macosm164.zip +.. _py310-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-310-v0.7.0-9cc1f5f-macosm164.zip +.. _py311-macosm164: https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.0-9cc1f5f-macosm164.zip 2. Unzip the downloaded file and copy the ``ifcopenshell`` directory into your Python path. If you're not sure where your Python path is, run the following From 837c401116a69b8dc27c0535f842491fd5e5c118 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 1 Sep 2023 17:28:19 +1000 Subject: [PATCH 55/81] Add filepath popup when saving IDS reports to BCF --- .../blenderbim/bim/module/tester/operator.py | 26 ++++++++----------- src/blenderbim/blenderbim/tool/tester.py | 22 ++++++++++++++++ 2 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 src/blenderbim/blenderbim/tool/tester.py diff --git a/src/blenderbim/blenderbim/bim/module/tester/operator.py b/src/blenderbim/blenderbim/bim/module/tester/operator.py index 71150627dc..4b88c3ae4b 100644 --- a/src/blenderbim/blenderbim/bim/module/tester/operator.py +++ b/src/blenderbim/blenderbim/bim/module/tester/operator.py @@ -68,6 +68,7 @@ class ExecuteIfcTester(bpy.types.Operator, tool.Ifc.Operator): report = None report = ifctester.reporter.Json(specs).report()["specifications"] if report: + tool.Tester.specs = specs tool.Tester.report = report props.specifications.clear() for spec in report: @@ -155,21 +156,16 @@ class ExportBcf(bpy.types.Operator): bl_idname = "bim.export_bcf" bl_label = "Export BCF" bl_options = {"REGISTER", "UNDO"} + filter_glob: bpy.props.StringProperty(default="*.bcf", options={"HIDDEN"}) + filepath: bpy.props.StringProperty(subtype="FILE_PATH") def execute(self, context): - props = context.scene.IfcTesterProperties - if tool.Ifc.get(): - ifc = tool.Ifc.get() - else: - ifc = ifcopenshell.open(props.ifc_file) - with tempfile.TemporaryDirectory() as dirpath: - output = os.path.join(dirpath, "{}.bcf".format(props.specs)) - specs = ifctester.ids.open(props.specs) - specs.validate(ifc) - bcf_reporter = ifctester.reporter.Bcf(specs) - bcf_reporter.report() - bcf_reporter.to_file(output) - print("Finished exporting!") - self.report({"INFO"}, "Finished exporting!") - + bcf_reporter = ifctester.reporter.Bcf(tool.Tester.specs) + bcf_reporter.report() + bcf_reporter.to_file(self.filepath) + self.report({"INFO"}, "Finished exporting!") return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} diff --git a/src/blenderbim/blenderbim/tool/tester.py b/src/blenderbim/blenderbim/tool/tester.py new file mode 100644 index 0000000000..f6f66e97ce --- /dev/null +++ b/src/blenderbim/blenderbim/tool/tester.py @@ -0,0 +1,22 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# 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 . + + +class Tester: + specs = None + report = {} From 04e9a08f3d96ff4df3ae36e4e9a34fa20788f88c Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 1 Sep 2023 17:29:06 +1000 Subject: [PATCH 56/81] IfcTester BCFs now include viewpoints for occurrences --- src/ifctester/ifctester/reporter.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ifctester/ifctester/reporter.py b/src/ifctester/ifctester/reporter.py index 4060198977..def76e8ef9 100644 --- a/src/ifctester/ifctester/reporter.py +++ b/src/ifctester/ifctester/reporter.py @@ -21,8 +21,11 @@ import sys import math import logging import datetime +import numpy as np import ifcopenshell +import ifcopenshell.util.unit import ifcopenshell.util.element +import ifcopenshell.util.placement cwd = os.path.dirname(os.path.realpath(__file__)) @@ -410,6 +413,7 @@ class Bcf(Json): def to_file(self, filepath): from bcf.v2.bcfxml import BcfXml + unit_scale = None bcfxml = BcfXml.create_new(self.results["title"]) for specification in self.results["specifications"]: if specification["status"]: @@ -419,11 +423,17 @@ class Bcf(Json): continue for failure in requirement["failed_entities"]: element = failure["element"] - title = f"ID:[{element.id()}]/GUID:[{element.GlobalId}]/{element.is_a()}/" + title = f"{element.is_a()}/" title += getattr(element, "Name", None) or "Unnamed" title += " - " + failure.get("reason", "No reason") description = f'{specification["name"]} - {requirement["description"]}' topic = bcfxml.add_topic(title, description, "IfcTester") + if getattr(element, "ObjectPlacement", None): + placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement) + if unit_scale is None: + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(element.wrapped_data.file) + location = [(o * unit_scale) + 5. for o in placement[:,3][:3]] + viewpoint = topic.add_viewpoint_from_point_and_guids(np.array(location), element.GlobalId) if element.is_a("IfcElement"): topic.add_viewpoint(element) bcfxml.save_project(filepath) From 0fcc28f50c8b26ee7ea4737387bd2977d8d44edf Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 1 Sep 2023 17:33:33 +1000 Subject: [PATCH 57/81] Minor fix --- src/ifctester/ifctester/reporter.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/ifctester/ifctester/reporter.py b/src/ifctester/ifctester/reporter.py index def76e8ef9..c982e1ec9b 100644 --- a/src/ifctester/ifctester/reporter.py +++ b/src/ifctester/ifctester/reporter.py @@ -369,7 +369,17 @@ class Ods(Json): continue table = Table(name=specification["name"]) tr = TableRow() - for header in ["Requirement", "Problem", "Class", "PredefinedType", "Name", "Description", "GlobalId", "Tag", "Element"]: + for header in [ + "Requirement", + "Problem", + "Class", + "PredefinedType", + "Name", + "Description", + "GlobalId", + "Tag", + "Element", + ]: tc = TableCell(valuetype="string", stylename="h") tc.addElement(P(text=header)) tr.addElement(tc) @@ -423,16 +433,21 @@ class Bcf(Json): continue for failure in requirement["failed_entities"]: element = failure["element"] - title = f"{element.is_a()}/" - title += getattr(element, "Name", None) or "Unnamed" - title += " - " + failure.get("reason", "No reason") + title_components = [ + element.is_a(), + getattr(element, "Name", None) or "Unnamed", + failure.get("reason", "No reason"), + getattr(element, "GlobalId", ""), + getattr(element, "Tag", ""), + ] + title = " - ".join(title_components) description = f'{specification["name"]} - {requirement["description"]}' topic = bcfxml.add_topic(title, description, "IfcTester") if getattr(element, "ObjectPlacement", None): placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement) if unit_scale is None: unit_scale = ifcopenshell.util.unit.calculate_unit_scale(element.wrapped_data.file) - location = [(o * unit_scale) + 5. for o in placement[:,3][:3]] + location = [(o * unit_scale) + 5.0 for o in placement[:, 3][:3]] viewpoint = topic.add_viewpoint_from_point_and_guids(np.array(location), element.GlobalId) if element.is_a("IfcElement"): topic.add_viewpoint(element) From 863bf8ebbee873a5355c1279587929d766fbeffc Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 1 Sep 2023 17:39:53 +1000 Subject: [PATCH 58/81] Fix bug where models that might have invalid shapes or 2D far shapes might break georeferencing and model loading. --- src/blenderbim/blenderbim/bim/import_ifc.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index 1ed67ac988..266cec2784 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -574,7 +574,13 @@ class IfcImporter: return if not self.does_element_likely_have_geometry_far_away(element): continue - shape = ifcopenshell.geom.create_shape(self.settings, element) + try: + shape = ifcopenshell.geom.create_shape(self.settings, element) + except: + try: + shape = ifcopenshell.geom.create_shape(self.settings_body_2d, element) + except: + continue m = shape.transformation.matrix.data mat = np.array( ([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]) From 7d7c04ddc02982ec6ac188cdb9f899670dd15bd7 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Mon, 28 Aug 2023 09:29:58 +0200 Subject: [PATCH 59/81] cmake format and unify file --- cmake/CMakeLists.txt | 1004 +++++++++++++++++++++++------------------- 1 file changed, 563 insertions(+), 441 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index f0ed33b0bc..6129b97fd1 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -19,7 +19,7 @@ cmake_minimum_required(VERSION 3.1.3) set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged +set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged project(IfcOpenShell VERSION 0.7.0) @@ -29,49 +29,54 @@ cmake_policy(SET CMP0078 OLD) cmake_policy(SET CMP0086 NEW) # use extra version to make pre-release using eg semver -set( EXTRA_VERSION "-alpha.3") +set(EXTRA_VERSION "-alpha.3") foreach(max_year RANGE 2014 2030) -set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}") -if (NOT "${max_sdk}" STREQUAL "") -MESSAGE(STATUS "Autodesk 3ds Max SDK found at ${max_sdk}") -set(HAS_MAX TRUE) -endif() + set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}") + + if(NOT "${max_sdk}" STREQUAL "") + message(STATUS "Autodesk 3ds Max SDK found at ${max_sdk}") + set(HAS_MAX TRUE) + endif() endforeach() -OPTION(MINIMAL_BUILD "The build is to make a minimal version of IFC converter from OCCT into IFC." OFF) -OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON) -OPTION(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON) -OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF) -OPTION(BUILD_PACKAGE "" OFF) -OPTION(BUILD_IFCGEOM "Build IfcGeom." ON) -OPTION(BUILD_DOCUMENTATION "Build IfcOpenShell Documentation." OFF) -OPTION(BUILD_IFCPYTHON "Build IfcPython." ON) -OPTION(BUILD_EXAMPLES "Build example applications." ON) -OPTION(BUILD_GEOMSERVER "Build IfcGeomServer executable." ON) -OPTION(BUILD_CONVERT "Build IfcConvert executable." ON) -OPTION(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON) -OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF) -OPTION(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF) -OPTION(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF) -OPTION(MSVC_PARALLEL_BUILD "Multi-threaded compilation in Microsoft Visual Studio (/MP)" OFF) + +option(MINIMAL_BUILD "The build is to make a minimal version of IFC converter from OCCT into IFC." OFF) +option(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON) +option(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON) +option(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF) +option(BUILD_PACKAGE "" OFF) +option(BUILD_IFCGEOM "Build IfcGeom." ON) +option(BUILD_DOCUMENTATION "Build IfcOpenShell Documentation." OFF) +option(BUILD_IFCPYTHON "Build IfcPython." ON) +option(BUILD_EXAMPLES "Build example applications." ON) +option(BUILD_GEOMSERVER "Build IfcGeomServer executable." ON) +option(BUILD_CONVERT "Build IfcConvert executable." ON) +option(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON) +option(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF) +option(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF) +option(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF) +option(MSVC_PARALLEL_BUILD "Multi-threaded compilation in Microsoft Visual Studio (/MP)" OFF) + OPTION(NO_WARN "Disable all warnings" OFF) OPTION(WASM_BUILD OFF) -if (${HAS_MAX}) -OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF) +if(${HAS_MAX}) + option(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF) endif() -if (${BUILD_CONVERT}) -OPTION(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF) + +if(${BUILD_CONVERT}) + option(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF) OPTION(USD_SUPPORT "Build IfcConvert with USD support (requires pixar's USD library)." OFF) endif() -OPTION(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF) -OPTION(ADD_COMMIT_SHA "Add commit sha and branch in version number, warning results in many rebuilds, requires git" OFF) -IF(NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE "Release") -ENDIF() +option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF) +option(ADD_COMMIT_SHA "Add commit sha and branch in version number, warning results in many rebuilds, requires git" OFF) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() if(MSVC AND MSVC_PARALLEL_BUILD) - add_definitions("/MP") + add_definitions("/MP") endif() if(NO_WARN) @@ -85,78 +90,93 @@ endif() # QtViewer requires Qt6 OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) include(GNUInstallDirs) -if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND (NOT BUILD_IFCGEOM)) + +if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND(NOT BUILD_IFCGEOM)) message(STATUS "'IfcGeom' is required with current outputs") set(BUILD_IFCGEOM ON) endif() # Specify where to install files -IF(NOT BINDIR) +if(NOT BINDIR) set(BINDIR bin) -ENDIF() -IF(NOT IS_ABSOLUTE ${BINDIR}) +endif() + +if(NOT IS_ABSOLUTE ${BINDIR}) set(BINDIR ${CMAKE_INSTALL_BINDIR}) -ENDIF() -MESSAGE(STATUS "BINDIR: ${BINDIR}") +endif() -IF(NOT INCLUDEDIR) +message(STATUS "BINDIR: ${BINDIR}") + +if(NOT INCLUDEDIR) set(INCLUDEDIR include) -ENDIF() -IF(NOT IS_ABSOLUTE ${INCLUDEDIR}) - set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) -ENDIF() -MESSAGE(STATUS "INCLUDEDIR: ${INCLUDEDIR}") +endif() -IF(NOT LIBDIR) +if(NOT IS_ABSOLUTE ${INCLUDEDIR}) + set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) +endif() + +message(STATUS "INCLUDEDIR: ${INCLUDEDIR}") + +if(NOT LIBDIR) set(LIBDIR lib) -ENDIF() -IF(NOT IS_ABSOLUTE ${LIBDIR}) +endif() + +if(NOT IS_ABSOLUTE ${LIBDIR}) set(LIBDIR ${CMAKE_INSTALL_LIBDIR}) -ENDIF() -MESSAGE(STATUS "LIBDIR: ${LIBDIR}") +endif() + +message(STATUS "LIBDIR: ${LIBDIR}") set(IFCOPENSHELL_LIBRARY_DIR "") # for *nix rpaths -if (BUILD_SHARED_LIBS) +if(BUILD_SHARED_LIBS) add_definitions(-DIFC_SHARED_BUILD) - if (MSVC) + + if(MSVC) message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.") + # C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' # There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx add_definitions(-wd4251) endif() + set(IFCOPENSHELL_LIBRARY_DIR "${LIBDIR}") endif() # Create cache entries if absent for environment variables -MACRO(UNIFY_ENVVARS_AND_CACHE VAR) - IF ((NOT DEFINED ${VAR}) AND (NOT "$ENV{${VAR}}" STREQUAL "")) - SET(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE) - ENDIF() -ENDMACRO() +macro(UNIFY_ENVVARS_AND_CACHE VAR) + if((NOT DEFINED ${VAR}) AND(NOT "$ENV{${VAR}}" STREQUAL "")) + set(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE) + endif() +endmacro() UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR) -if (NOT MINIMAL_BUILD) -UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR) -UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR) -UNIFY_ENVVARS_AND_CACHE(LIBXML2_INCLUDE_DIR) -UNIFY_ENVVARS_AND_CACHE(LIBXML2_LIBRARIES) -UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR) -UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE) -UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR) -UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR) -UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARIES) -UNIFY_ENVVARS_AND_CACHE(CGAL_INCLUDE_DIR) -UNIFY_ENVVARS_AND_CACHE(CGAL_LIBRARY_DIR) -UNIFY_ENVVARS_AND_CACHE(GMP_INCLUDE_DIR) -UNIFY_ENVVARS_AND_CACHE(GMP_LIBRARY_DIR) -UNIFY_ENVVARS_AND_CACHE(MPFR_INCLUDE_DIR) -UNIFY_ENVVARS_AND_CACHE(MPFR_LIBRARY_DIR) + +if(NOT MINIMAL_BUILD) + UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR) + UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR) + UNIFY_ENVVARS_AND_CACHE(LIBXML2_INCLUDE_DIR) + UNIFY_ENVVARS_AND_CACHE(LIBXML2_LIBRARIES) + UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR) + UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE) + UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR) + UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR) + UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARIES) endif() + UNIFY_ENVVARS_AND_CACHE(BOOST_ROOT) UNIFY_ENVVARS_AND_CACHE(BOOST_LIBRARYDIR) +if(NOT MINIMAL_BUILD) + UNIFY_ENVVARS_AND_CACHE(CGAL_INCLUDE_DIR) + UNIFY_ENVVARS_AND_CACHE(CGAL_LIBRARY_DIR) + UNIFY_ENVVARS_AND_CACHE(GMP_INCLUDE_DIR) + UNIFY_ENVVARS_AND_CACHE(GMP_LIBRARY_DIR) + UNIFY_ENVVARS_AND_CACHE(MPFR_INCLUDE_DIR) + UNIFY_ENVVARS_AND_CACHE(MPFR_LIBRARY_DIR) +endif() + if(WASM_BUILD) # when using the nix/build-all.py build script we should not # look into the sysroot for most of the dependencies but rather @@ -165,16 +185,18 @@ if(WASM_BUILD) set(CMAKE_FIND_ROOT_PATH "") endif() -if (NOT MINIMAL_BUILD AND GLTF_SUPPORT AND BUILD_CONVERT) -UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR) -FIND_FILE(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann) -IF(json_hpp) - MESSAGE(STATUS "JSON for Modern C++ header file found") -ELSE() - MESSAGE(FATAL_ERROR "Unable to find JSON for Modern C++ header file, aborting") -ENDIF() -add_definitions(-DWITH_GLTF) -set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_GLTF) +if(NOT MINIMAL_BUILD AND GLTF_SUPPORT AND BUILD_CONVERT) + UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR) + FIND_FILE(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann) + + if(json_hpp) + message(STATUS "JSON for Modern C++ header file found") + else() + message(FATAL_ERROR "Unable to find JSON for Modern C++ header file, aborting") + endif() + + add_definitions(-DWITH_GLTF) + set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_GLTF) endif() # Add USD support to serializers @@ -226,42 +248,48 @@ if(NOT MINIMAL_BUILD AND USD_SUPPORT) endif() # Set INSTALL_RPATH for target -MACRO(SET_INSTALL_RPATHS _target _paths) - SET(${_target}_rpaths "") - FOREACH(_path ${_paths}) - LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_path}" isSystemDir) - IF("${isSystemDir}" STREQUAL "-1") - LIST(APPEND ${_target}_rpaths ${_path}) - ENDIF() - ENDFOREACH() - MESSAGE(STATUS "Set INSTALL_RPATH for ${_target}: ${${_target}_rpaths}") - SET_TARGET_PROPERTIES(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}") -ENDMACRO() +macro(SET_INSTALL_RPATHS _target _paths) + set(${_target}_rpaths "") + + foreach(_path ${_paths}) + list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_path}" isSystemDir) + + if("${isSystemDir}" STREQUAL "-1") + list(APPEND ${_target}_rpaths ${_path}) + endif() + endforeach() + + message(STATUS "Set INSTALL_RPATH for ${_target}: ${${_target}_rpaths}") + set_target_properties(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}") +endmacro() # Find Boost: On win32 the (hardcoded) default is to use static libraries and # runtime, when doing running conda-build we pick what conda prepared for us. -IF(WIN32 AND ("$ENV{CONDA_BUILD}" STREQUAL "")) - SET(Boost_USE_STATIC_LIBS ON) - SET(Boost_USE_STATIC_RUNTIME OFF) - SET(Boost_USE_MULTITHREADED ON) +if(WIN32 AND("$ENV{CONDA_BUILD}" STREQUAL "")) + set(Boost_USE_STATIC_LIBS ON) + set(Boost_USE_STATIC_RUNTIME OFF) + set(Boost_USE_MULTITHREADED ON) + # Disable Boost's autolinking as the libraries to be linked to are supplied # already by CMake, and wrong libraries would be asked for when code is # compiled with a toolset different from default. if(MSVC) - ADD_DEFINITIONS(-DBOOST_ALL_NO_LIB) + add_definitions(-DBOOST_ALL_NO_LIB) + # Necessary for boost version >= 1.67 - SET(BCRYPT_LIBRARIES "bcrypt.lib") - ENDIF() -ELSE() + set(BCRYPT_LIBRARIES "bcrypt.lib") + endif() +else() # Disable Boost's autolinking as the libraries to be linked to are supplied # already by CMake, and it's going to conflict if there are multiple, as is # the case in conda-forge's libboost feedstock. - ADD_DEFINITIONS(-DBOOST_ALL_NO_LIB) - IF(WIN32) + add_definitions(-DBOOST_ALL_NO_LIB) + + if(WIN32) # Necessary for boost version >= 1.67 - SET(BCRYPT_LIBRARIES "bcrypt.lib") - ENDIF() -ENDIF() + set(BCRYPT_LIBRARIES "bcrypt.lib") + endif() +endif() if (WASM_BUILD) set(BOOST_COMPONENTS) @@ -278,6 +306,7 @@ if(USE_MMAP) else() set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams) endif() + add_definitions(-DUSE_MMAP) endif() @@ -285,16 +314,20 @@ FIND_PACKAGE(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}") MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}") -if (NOT MINIMAL_BUILD) -# libxml2 is required for IFCXML (optional) and SVGFILL (mandatory) - find_package(LibXml2 REQUIRED) +if(NOT MINIMAL_BUILD) + # libxml2 is required for IFCXML (optional) and SVGFILL (mandatory) + find_package(LibXml2 REQUIRED) endif() -if (NOT MINIMAL_BUILD AND IFCXML_SUPPORT) +if(NOT MINIMAL_BUILD AND IFCXML_SUPPORT) add_definitions(-DWITH_IFCXML) - set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_IFCXML) + set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_IFCXML) endif() +find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +message(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}") +message(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}") + # Usage: # set(SOME_LIRARIES foo bar) # add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" d) @@ -308,10 +341,12 @@ endif() function(add_debug_variants NAME LIBRARIES POSTFIX) set(LIBRARIES_STR "${LIBRARIES}") set(LIBRARIES "") + # the result, "optimized debug ", needs to be a list instead of a string foreach(lib ${LIBRARIES_STR}) list(APPEND LIBRARIES optimized) - if ("${lib}" MATCHES ".lib") + + if("${lib}" MATCHES ".lib") string(REPLACE ".lib" "" lib ${lib}) list(APPEND LIBRARIES ${lib}.lib) else() @@ -319,92 +354,97 @@ function(add_debug_variants NAME LIBRARIES POSTFIX) endif() list(APPEND LIBRARIES debug) - if ("${lib}" MATCHES ".lib") + + if("${lib}" MATCHES ".lib") string(REPLACE ".lib" "" lib ${lib}) list(APPEND LIBRARIES ${lib}${POSTFIX}.lib) else() list(APPEND LIBRARIES ${lib}${POSTFIX}) endif() endforeach() + set(${NAME} ${LIBRARIES} PARENT_SCOPE) endfunction() if(BUILD_IFCGEOM) + if(MSVC) + add_debug_variants(LIBXML2_LIBRARIES "${LIBXML2_LIBRARIES}" d) + endif() -IF(MSVC) - add_debug_variants(LIBXML2_LIBRARIES "${LIBXML2_LIBRARIES}" d) -ENDIF() - -# Open CASCADE -IF("${OCC_INCLUDE_DIR}" STREQUAL "") - FIND_PATH(OCC_INCLUDE_DIR Standard_Version.hxx - [PATHS + # Open CASCADE + if("${OCC_INCLUDE_DIR}" STREQUAL "") + find_path(OCC_INCLUDE_DIR Standard_Version.hxx + [PATHS /usr/include/occt /usr/include/oce /usr/include/opencascade - ] - REQUIRED + ] + REQUIRED + ) + + if(OCC_INCLUDE_DIR) + message(STATUS "Found Open CASCADE include files in: ${OCC_INCLUDE_DIR}") + else() + message(FATAL_ERROR "Unable to find Open CASCADE include directory, specify OCC_INCLUDE_DIR manually.") + endif() + else() + set(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files") + message(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}") + endif() + + set(OPENCASCADE_LIBRARY_NAMES + TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO + TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset TKHLR + + # @todo investigate the exact conditions when this is necessary + TKBin ) - IF(OCC_INCLUDE_DIR) - MESSAGE(STATUS "Found Open CASCADE include files in: ${OCC_INCLUDE_DIR}") - ELSE() - MESSAGE(FATAL_ERROR "Unable to find Open CASCADE include directory, specify OCC_INCLUDE_DIR manually.") - ENDIF() -ELSE() - SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files") - MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}") -ENDIF() -SET(OPENCASCADE_LIBRARY_NAMES - TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO - TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset TKHLR - - # @todo investigate the exact conditions when this is necessary - TKBin -) - -IF("${OCC_LIBRARY_DIR}" STREQUAL "") - find_library(OCC_LIBRARY TKernel - [PATHS + if("${OCC_LIBRARY_DIR}" STREQUAL "") + find_library(OCC_LIBRARY TKernel + [PATHS /usr/lib - ] - REQUIRED - ) - IF(OCC_LIBRARY) - GET_FILENAME_COMPONENT(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH) - MESSAGE(STATUS "Found Open CASCADE library files in: ${OCC_LIBRARY_DIR}") - ELSE() - MESSAGE(FATAL_ERROR "Unable find Open CASCADE library directory, specify OCC_LIBRARY_DIR manually.") - ENDIF() -ELSE() - SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files") - MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}") -ENDIF() + ] + REQUIRED + ) -FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH) -IF(libTKernel) - MESSAGE(STATUS "Required Open Cascade Library files found") -ELSE() - MESSAGE(FATAL_ERROR "Unable to find Open Cascade library files, aborting") -ENDIF() + if(OCC_LIBRARY) + GET_FILENAME_COMPONENT(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH) + message(STATUS "Found Open CASCADE library files in: ${OCC_LIBRARY_DIR}") + else() + message(FATAL_ERROR "Unable find Open CASCADE library directory, specify OCC_LIBRARY_DIR manually.") + endif() + else() + set(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files") + message(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}") + endif() -# Use the found libTKernel as a template for all other OCC libraries -# TODO Extract this into macro/function -foreach(lib ${OPENCASCADE_LIBRARY_NAMES}) - # Make sure we'll handle the Windows/MSVC debug postfix convention too. - string(REPLACE TKerneld "${lib}" lib_path "${libTKernel}") - string(REPLACE TKernel "${lib}" lib_path "${lib_path}") - list(APPEND OPENCASCADE_LIBRARIES "${lib_path}") -endforeach() + find_library(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH) -if(MSVC) - add_definitions(-DHAVE_NO_DLL) - add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d) -endif() -if (WIN32) - # OCC might require linking to Winsock depending on the version and build configuration - list(APPEND OPENCASCADE_LIBRARIES ws2_32.lib) -endif() + if(libTKernel) + message(STATUS "Required Open Cascade Library files found") + else() + message(FATAL_ERROR "Unable to find Open Cascade library files, aborting") + endif() + + # Use the found libTKernel as a template for all other OCC libraries + # TODO Extract this into macro/function + foreach(lib ${OPENCASCADE_LIBRARY_NAMES}) + # Make sure we'll handle the Windows/MSVC debug postfix convention too. + string(REPLACE TKerneld "${lib}" lib_path "${libTKernel}") + string(REPLACE TKernel "${lib}" lib_path "${lib_path}") + list(APPEND OPENCASCADE_LIBRARIES "${lib_path}") + endforeach() + + if(MSVC) + add_definitions(-DHAVE_NO_DLL) + add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d) + endif() + + if(WIN32) + # OCC might require linking to Winsock depending on the version and build configuration + list(APPEND OPENCASCADE_LIBRARIES ws2_32.lib) + endif() # Make sure cross-referenced symbols between static OCC libraries get # resolved. Also add thread and rt libraries. @@ -438,67 +478,71 @@ endif() endif(BUILD_IFCGEOM) -IF(NOT MINIMAL_BUILD AND COLLADA_SUPPORT) - # Find OpenCOLLADA - IF("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "") - MESSAGE(STATUS "No OpenCOLLADA include directory specified") - SET(OPENCOLLADA_INCLUDE_DIR "/usr/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files") - ELSE() - SET(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files") - ENDIF() +if(NOT MINIMAL_BUILD AND COLLADA_SUPPORT) + # Find OpenCOLLADA + if("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "") + message(STATUS "No OpenCOLLADA include directory specified") + set(OPENCOLLADA_INCLUDE_DIR "/usr/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files") + else() + set(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files") + endif() - IF("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "") - MESSAGE(STATUS "No OpenCOLLADA library directory specified") - FIND_LIBRARY(OPENCOLLADA_FRAMEWORK_LIB NAMES OpenCOLLADAFramework - PATHS /usr/lib64/opencollada /usr/lib/opencollada /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib) - GET_FILENAME_COMPONENT(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_FRAMEWORK_LIB} PATH) - ENDIF() + if("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "") + message(STATUS "No OpenCOLLADA library directory specified") + find_library(OPENCOLLADA_FRAMEWORK_LIB NAMES OpenCOLLADAFramework + PATHS /usr/lib64/opencollada /usr/lib/opencollada /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib) + get_filename_component(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_FRAMEWORK_LIB} PATH) + endif() - FIND_LIBRARY(OpenCOLLADAFramework NAMES OpenCOLLADAFramework OpenCOLLADAFrameworkd PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH) - if (OpenCOLLADAFramework) + find_library(OpenCOLLADAFramework NAMES OpenCOLLADAFramework OpenCOLLADAFrameworkd PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH) + + if(OpenCOLLADAFramework) message(STATUS "OpenCOLLADA library files found") else() message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA libraries. " "Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.") endif() - SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files") + set(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files") - SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter") + set(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter") - FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS}) - IF(COLLADASWStreamWriter_h) - MESSAGE(STATUS "OpenCOLLADA header files found") - ADD_DEFINITIONS(-DWITH_OPENCOLLADA) - set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_OPENCOLLADA) + find_file(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS}) - SET(OPENCOLLADA_LIBRARY_NAMES - GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader - OpenCOLLADAStreamWriter UTF buffer ftoa - ) + IF(COLLADASWStreamWriter_h) + message(STATUS "OpenCOLLADA header files found") + add_definitions(-DWITH_OPENCOLLADA) + set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_OPENCOLLADA) - # Use the found OpenCOLLADAFramework as a template for all other OpenCOLLADA libraries - foreach(lib ${OPENCOLLADA_LIBRARY_NAMES}) + set(OPENCOLLADA_LIBRARY_NAMES + GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader + OpenCOLLADAStreamWriter UTF buffer ftoa + ) + + # Use the found OpenCOLLADAFramework as a template for all other OpenCOLLADA libraries + foreach(lib ${OPENCOLLADA_LIBRARY_NAMES}) # Make sure we'll handle the Windows/MSVC debug postfix convention too. string(REPLACE OpenCOLLADAFrameworkd "${lib}" lib_path "${OpenCOLLADAFramework}") string(REPLACE OpenCOLLADAFramework "${lib}" lib_path "${lib_path}") - list(APPEND OPENCOLLADA_LIBRARIES "${lib_path}") - endforeach() + list(APPEND OPENCOLLADA_LIBRARIES "${lib_path}") + endforeach() - if("${PCRE_LIBRARY_DIR}" STREQUAL "") + if("${PCRE_LIBRARY_DIR}" STREQUAL "") if(WIN32) find_library(pcre_library NAMES pcre pcred PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH) else() find_library(pcre_library NAMES pcre PATHS ${OPENCOLLADA_LIBRARY_DIR}) endif() - GET_FILENAME_COMPONENT(PCRE_LIBRARY_DIR ${pcre_library} PATH) - else() - find_library(pcre_library NAMES pcre pcred PATHS ${PCRE_LIBRARY_DIR} NO_DEFAULT_PATH) - endif() - if (pcre_library) - SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR}) - if (MSVC) + get_filename_component(PCRE_LIBRARY_DIR ${pcre_library} PATH) + else() + find_library(pcre_library NAMES pcre pcred PATHS ${PCRE_LIBRARY_DIR} NO_DEFAULT_PATH) + endif() + + if(pcre_library) + set(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR}) + + if(MSVC) # Add release lib regardless whether release or debug found. Debug version will be appended below. list(APPEND OPENCOLLADA_LIBRARIES "${PCRE_LIBRARY_DIR}/pcre.lib") else() @@ -507,61 +551,59 @@ IF(NOT MINIMAL_BUILD AND COLLADA_SUPPORT) else() message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find PCRE. " "Disable COLLADA_SUPPORT or fix PCRE_LIBRARY_DIR path to proceed.") - endif() + endif() - IF(MSVC) - add_debug_variants(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" d) - ENDIF() - ELSE() + if(MSVC) + add_debug_variants(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" d) + endif() + else() message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA headers. " "Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.") - ENDIF() -ENDIF() + endif() +endif() if(NOT MINIMAL_BUILD AND HDF5_SUPPORT) - IF("${HDF5_INCLUDE_DIR}" STREQUAL "") - MESSAGE(STATUS "No HDF5 include directory specified") - ElSE() - SET(HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIR}" CACHE FILEPATH "HDF5 header files") - ENDIF() - - IF("${HDF5_LIBRARY_DIR}" STREQUAL "") - MESSAGE(STATUS "No HDF5 library directory specified") - ElSE() - SET(HDF5_LIBRARY_DIR "${HDF5_LIBRARY_DIR}" CACHE FILEPATH "HDF5 library files") - ENDIF() + if("${HDF5_INCLUDE_DIR}" STREQUAL "") + message(STATUS "No HDF5 include directory specified") + else() + set(HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIR}" CACHE FILEPATH "HDF5 header files") + endif() - if (HDF5_LIBRARY_DIR) - # result of the HDF5 ctest package + if("${HDF5_LIBRARY_DIR}" STREQUAL "") + message(STATUS "No HDF5 library directory specified") + else() + set(HDF5_LIBRARY_DIR "${HDF5_LIBRARY_DIR}" CACHE FILEPATH "HDF5 library files") + endif() + + if(HDF5_LIBRARY_DIR) + # result of the HDF5 ctest package # Find zlib using cmake find_library. How should this be implemented? # FIND_LIBRARY(NAMES z libz libz_debug PATHS ... NO_DEFAULT_PATH) - - - if ("$ENV{CONDA_BUILD}" STREQUAL "") + if("$ENV{CONDA_BUILD}" STREQUAL "") # result of the HDF5 ctest package - - if (WIN32) + if(WIN32) set(zlib_post lib) set(lib_ext lib) else() set(lib_ext a) endif() - if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") set(debug_postfix "_debug") endif() - SET(HDF5_LIBRARIES - "${HDF5_LIBRARY_DIR}/libhdf5_cpp${debug_postfix}.${lib_ext}" - "${HDF5_LIBRARY_DIR}/libhdf5${debug_postfix}.${lib_ext}" - "${HDF5_LIBRARY_DIR}/libz${zlib_post}${debug_postfix}.${lib_ext}" - "${HDF5_LIBRARY_DIR}/libsz${debug_postfix}.${lib_ext}" - "${HDF5_LIBRARY_DIR}/libaec${debug_postfix}.${lib_ext}" - ) + set(HDF5_LIBRARIES + "${HDF5_LIBRARY_DIR}/libhdf5_cpp${debug_postfix}.${lib_ext}" + "${HDF5_LIBRARY_DIR}/libhdf5${debug_postfix}.${lib_ext}" + "${HDF5_LIBRARY_DIR}/libz${zlib_post}${debug_postfix}.${lib_ext}" + "${HDF5_LIBRARY_DIR}/libsz${debug_postfix}.${lib_ext}" + "${HDF5_LIBRARY_DIR}/libaec${debug_postfix}.${lib_ext}" + ) - ELSE() - MESSAGE(STATUS "Packaging hdf5 and zlib for conda distribution") - if (WIN32) + else() + message(STATUS "Packaging hdf5 and zlib for conda distribution") + + if(WIN32) # Windows set(zlib_post zlib) set(lib_ext lib) @@ -575,19 +617,17 @@ if(NOT MINIMAL_BUILD AND HDF5_SUPPORT) 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() - if (NOT HDF5_LIBRARIES) - # debian default - - SET(HDF5_LIBRARIES + if(NOT HDF5_LIBRARIES) + # debian default + set(HDF5_LIBRARIES /usr/lib/x86_64-linux-gnu/hdf5/serial/libhdf5_cpp.so /usr/lib/x86_64-linux-gnu/hdf5/serial/libhdf5.so /usr/lib/x86_64-linux-gnu/libsz.so @@ -595,96 +635,108 @@ if(NOT MINIMAL_BUILD AND HDF5_SUPPORT) z dl ) endif() - + add_definitions(-DWITH_HDF5) - set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_HDF5) + set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_HDF5) endif() if(ENABLE_BUILD_OPTIMIZATIONS) - if(MSVC) + if(MSVC) # NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default, # with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance # of IfcConvert significantly. # TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse) - # C++ - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi") - # Linker - # /OPT:REF enables also /OPT:ICF and disables INCREMENTAL - set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF") - # /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx) - set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF") - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF") - set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF") - else() + # C++ + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi") + + # Linker + # /OPT:REF enables also /OPT:ICF and disables INCREMENTAL + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF") + + # /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx) + set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF") + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF") + else() # GCC-like: Release should use O3 but RelWithDebInfo 02 so enforce 03. Anything other useful that could be added here? set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3") - endif() + endif() endif() -IF(MSVC) - # warning due to virtual inheritance - ADD_DEFINITIONS(-wd4250) - # warning due to select definitions in the schema being redundant - ADD_DEFINITIONS(-wd4584) - - # didn't work well on ifcopenbot, @todo make configurable - # add_definitions(/MP) +if(MSVC) + # warning due to virtual inheritance + add_definitions(-wd4250) + + # warning due to select definitions in the schema being redundant + add_definitions(-wd4584) + + # didn't work well on ifcopenbot, @todo make configurable + # add_definitions(/MP) # Enable solution folders (free VS versions prior to 2012 don't support solution folders) - if (MSVC_VERSION GREATER 1600) + if(MSVC_VERSION GREATER 1600) set_property(GLOBAL PROPERTY USE_FOLDERS ON) endif() - IF(USE_VLD) - ADD_DEFINITIONS(-DUSE_VLD) - ENDIF() - # Enforce Unicode for CRT and Win32 API calls - ADD_DEFINITIONS(-D_UNICODE -DUNICODE) - # Disable warnings about unsafe C functions; we could use the safe C99 & C11 versions if we have no need for supporting old compilers. - ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS) - ADD_DEFINITIONS(-bigobj) # required for building the big ifcXXX.objs, https://msdn.microsoft.com/en-us/library/ms173499.aspx - # Bump up the warning level from the default 3 to 4. - ADD_DEFINITIONS(-W4) - IF(MSVC_VERSION GREATER 1800) # > 2013 - # Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now. - ADD_DEFINITIONS(-wd4458) - ENDIF() + if(USE_VLD) + add_definitions(-DUSE_VLD) + endif() + + # Enforce Unicode for CRT and Win32 API calls + add_definitions(-D_UNICODE -DUNICODE) + + # Disable warnings about unsafe C functions; we could use the safe C99 & C11 versions if we have no need for supporting old compilers. + add_definitions(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS) + add_definitions(-bigobj) # required for building the big ifcXXX.objs, https://msdn.microsoft.com/en-us/library/ms173499.aspx + + # Bump up the warning level from the default 3 to 4. + add_definitions(-W4) + + if(MSVC_VERSION GREATER 1800) # > 2013 + # Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now. + add_definitions(-wd4458) + endif() + # Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this - if (MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66)) + if(MSVC_VERSION GREATER 1900 AND(Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66)) add_definitions(-permissive-) endif() - # Link against the static VC runtime - # TODO Make this configurable - # IF("$ENV{CONDA_BUILD}" STREQUAL "") - # FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL - # CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE - # CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) - # IF(${flag} MATCHES "/MD") - # STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}") - # ENDIF() - # IF(${flag} MATCHES "/MDd") - # STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}") - # ENDIF() - # ENDFOREACH() - # ENDIF() -ElSE() + +# Link against the static VC runtime +# TODO Make this configurable +# IF("$ENV{CONDA_BUILD}" STREQUAL "") +# FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL +# CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE +# CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) +# IF(${flag} MATCHES "/MD") +# STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}") +# ENDIF() +# IF(${flag} MATCHES "/MDd") +# STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}") +# ENDIF() +# ENDFOREACH() +# ENDIF() +else() add_definitions(-Wall -Wextra) - if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_definitions(-Wno-tautological-constant-out-of-range-compare) else() add_definitions(-Wno-maybe-uninitialized) endif() - if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0)) + + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0)) # OpenCascade spews a lot of deprecated-copy warnings add_definitions(-Wno-deprecated-copy) endif() + # -fPIC is not relevant on Windows and creates pointless warnings - if (UNIX) + if(UNIX) add_definitions(-fPIC) endif() -ENDIF() +endif() INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} ${JSON_INCLUDE_DIR} ${HDF5_INCLUDE_DIR} @@ -697,7 +749,7 @@ function(files_for_ifc_version IFC_VERSION RESULT_NAME) ${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h ${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h ${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp - PARENT_SCOPE + PARENT_SCOPE ) endfunction() @@ -711,38 +763,43 @@ if(NOT SCHEMA_VERSIONS) endif() foreach(s ${SCHEMA_VERSIONS}) - add_definitions(-DHAS_SCHEMA_${s}) + add_definitions(-DHAS_SCHEMA_${s}) endforeach() string(REPLACE ";" ")(" schema_version_seq "(${SCHEMA_VERSIONS})") -ADD_DEFINITIONS(-DSCHEMA_SEQ=${schema_version_seq}) +add_definitions(-DSCHEMA_SEQ=${schema_version_seq}) if(COMPILE_SCHEMA) - # @todo, this appears to be untested at the moment - + # @todo, this appears to be untested at the moment find_package(PythonInterp) - IF(NOT PYTHONINTERP_FOUND) - MESSAGE(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.") - ENDIF() + if(NOT PYTHONINTERP_FOUND) + message(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.") + endif() set(IFC_RELEASE_NOT_USED ${SCHEMA_VERSIONS}) # Install pyparsing if necessary execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST) - if ("${PYTHON_PACKAGE_LIST}" STREQUAL "") + + if("${PYTHON_PACKAGE_LIST}" STREQUAL "") execute_process(COMMAND pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST) - if ("${PYTHON_PACKAGE_LIST}" STREQUAL "") + + if("${PYTHON_PACKAGE_LIST}" STREQUAL "") message(WARNING "Failed to find pip. Pip is required to automatically install pyparsing") endif() endif() + string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND) - if ("${PYPARSING_FOUND}" STREQUAL "-1") + + if("${PYPARSING_FOUND}" STREQUAL "-1") message(STATUS "Installing pyparsing") execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS) - if (NOT "${SUCCESS}" STREQUAL "0") + + if(NOT "${SUCCESS}" STREQUAL "0") execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS) - if (NOT "${SUCCESS}" STREQUAL "0") + + if(NOT "${SUCCESS}" STREQUAL "0") message(WARNING "Failed to automatically install pyparsing. Please install manually") endif() endif() @@ -757,8 +814,8 @@ if(COMPILE_SCHEMA) OUTPUT_FILE express_parser.py RESULT_VARIABLE SUCCESS) - if (NOT "${SUCCESS}" STREQUAL "0") - MESSAGE(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed") + if(NOT "${SUCCESS}" STREQUAL "0") + message(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed") endif() # Generate code @@ -767,11 +824,11 @@ if(COMPILE_SCHEMA) OUTPUT_VARIABLE COMPILED_SCHEMA_NAME) # Prevent the schema that had just been compiled from being excluded - foreach(s ${SCHEMA_VERSIONS}) - if("${COMPILED_SCHEMA_NAME}" STREQUAL "${s}") - list(REMOVE_ITEM IFC_RELEASE_NOT_USED "${s}") - endif() - endforeach() + foreach(s ${SCHEMA_VERSIONS}) + if("${COMPILED_SCHEMA_NAME}" STREQUAL "${s}") + list(REMOVE_ITEM IFC_RELEASE_NOT_USED "${s}") + endif() + endforeach() endif() # Boost >= 1.58 requires BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE to build on some Linux distros. @@ -802,31 +859,32 @@ file(GLOB IFCPARSE_H_FILES_ALL ../src/ifcparse/*.h) file(GLOB IFCPARSE_CPP_FILES_ALL ../src/ifcparse/*.cpp) foreach(s ${IFCPARSE_H_FILES_ALL}) -get_filename_component(p "${s}" NAME) -if (NOT "${p}" MATCHES "[0-9]") -list(APPEND IFCPARSE_H_FILES "${s}") -endif() + get_filename_component(p "${s}" NAME) + + if(NOT "${p}" MATCHES "[0-9]") + list(APPEND IFCPARSE_H_FILES "${s}") + endif() endforeach() foreach(s ${IFCPARSE_CPP_FILES_ALL}) -get_filename_component(p "${s}" NAME) -if (NOT "${p}" MATCHES "[0-9]") -list(APPEND IFCPARSE_CPP_FILES "${s}") -endif() + get_filename_component(p "${s}" NAME) + + if(NOT "${p}" MATCHES "[0-9]") + list(APPEND IFCPARSE_CPP_FILES "${s}") + endif() endforeach() foreach(s ${SCHEMA_VERSIONS}) - list(APPEND IFCPARSE_H_FILES - ../src/ifcparse/Ifc${s}.h - ../src/ifcparse/Ifc${s}-definitions.h - ) - list(APPEND IFCPARSE_CPP_FILES - ../src/ifcparse/Ifc${s}.cpp - ../src/ifcparse/Ifc${s}-schema.cpp - ) + list(APPEND IFCPARSE_H_FILES + ../src/ifcparse/Ifc${s}.h + ../src/ifcparse/Ifc${s}-definitions.h + ) + list(APPEND IFCPARSE_CPP_FILES + ../src/ifcparse/Ifc${s}.cpp + ../src/ifcparse/Ifc${s}-schema.cpp + ) endforeach() - set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES}) add_library(IfcParse ${IFCPARSE_FILES}) @@ -838,12 +896,12 @@ else() TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES}) endif() -if (BUILD_IFCGEOM) -# IfcGeom -file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h ../src/ifcgeom/*.i) -file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) -set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) +if(BUILD_IFCGEOM) + # IfcGeom + file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h ../src/ifcgeom/*.i) + file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) + set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) foreach(s ${SCHEMA_VERSIONS}) add_library(IfcGeom_ifc${s} STATIC ${IFCGEOM_FILES}) @@ -853,17 +911,17 @@ foreach(s ${SCHEMA_VERSIONS}) endif() endforeach() -# IfcGeom (schema agnostic) -file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic/*.h) -file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic/*.cpp) -set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) + # IfcGeom (schema agnostic) + file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic/*.h) + file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic/*.cpp) + set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) -add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES}) -set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS VERSION "0.6.0" SOVERSION "0.6") + add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES}) + set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS VERSION "0.6.0" SOVERSION "0.6") -if (UNIX) -find_package(Threads) -endif() + if(UNIX) + find_package(Threads) + endif() if (WASM_BUILD) TARGET_LINK_LIBRARIES(IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) @@ -873,15 +931,14 @@ endif() endif(BUILD_IFCGEOM) -if (BUILD_CONVERT OR BUILD_IFCPYTHON) - -# Serializers -file(GLOB SERIALIZERS_H_FILES ../src/serializers/*.h) -file(GLOB SERIALIZERS_CPP_FILES ../src/serializers/*.cpp) -set(SERIALIZERS_FILES ${SERIALIZERS_H_FILES} ${SERIALIZERS_CPP_FILES}) -file(GLOB SERIALIZERS_S_H_FILES ../src/serializers/schema_dependent/*.h) -file(GLOB SERIALIZERS_S_CPP_FILES ../src/serializers/schema_dependent/*.cpp) -set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES}) +if(BUILD_CONVERT OR BUILD_IFCPYTHON) + # Serializers + file(GLOB SERIALIZERS_H_FILES ../src/serializers/*.h) + file(GLOB SERIALIZERS_CPP_FILES ../src/serializers/*.cpp) + set(SERIALIZERS_FILES ${SERIALIZERS_H_FILES} ${SERIALIZERS_CPP_FILES}) + file(GLOB SERIALIZERS_S_H_FILES ../src/serializers/schema_dependent/*.h) + file(GLOB SERIALIZERS_S_CPP_FILES ../src/serializers/schema_dependent/*.cpp) + set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES}) foreach(s ${SCHEMA_VERSIONS}) add_library(Serializers_ifc${s} STATIC ${SERIALIZERS_S_FILES}) @@ -894,58 +951,122 @@ foreach(s ${SCHEMA_VERSIONS}) endif() endforeach() -add_library(Serializers ${SERIALIZERS_FILES}) -set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}" VERSION "0.6.0" SOVERSION "0.6") + add_library(Serializers ${SERIALIZERS_FILES}) + set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}" VERSION "0.6.0" SOVERSION "0.6") TARGET_LINK_LIBRARIES(Serializers ${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES}) endif(BUILD_CONVERT OR BUILD_IFCPYTHON) -if (BUILD_CONVERT) - -# IfcConvert -file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp) -file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h) -set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES}) -ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES}) -set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}") +if(BUILD_CONVERT) + # IfcConvert + file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp) + file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h) + set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES}) + add_executable(IfcConvert ${IFCCONVERT_FILES}) + set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}") TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${HDF5_LIBRARIES} ${USD_LIBRARIES}) -if ((NOT WIN32) AND BUILD_SHARED_LIBS) - # Only set RPATHs when building shared libraries (i.e. IfcParse and - # IfcGeom are dynamically linked). Not necessarily a perfect solution - # but probably a good indication of whether RPATHs are necessary. - SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBRARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR}") -endif() - -INSTALL(TARGETS IfcConvert - ARCHIVE DESTINATION ${LIBDIR} - LIBRARY DESTINATION ${LIBDIR} - RUNTIME DESTINATION ${BINDIR} -) + if((NOT WIN32) AND BUILD_SHARED_LIBS) + # Only set RPATHs when building shared libraries (i.e. IfcParse and + # IfcGeom are dynamically linked). Not necessarily a perfect solution + # but probably a good indication of whether RPATHs are necessary. + SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBRARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR}") + endif() + install(TARGETS IfcConvert + ARCHIVE DESTINATION ${LIBDIR} + LIBRARY DESTINATION ${LIBDIR} + RUNTIME DESTINATION ${BINDIR} + ) endif(BUILD_CONVERT) # IfcGeomServer if(NOT MINIMAL_BUILD AND BUILD_GEOMSERVER) + file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp) + file(GLOB H_FILES ../src/ifcgeomserver/*.h) + set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) + add_executable(IfcGeomServer ${SOURCE_FILES}) + target_link_libraries(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES}) -file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp) -file(GLOB H_FILES ../src/ifcgeomserver/*.h) -set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) -ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES}) -TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES}) + if((NOT WIN32) AND BUILD_SHARED_LIBS) + SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBRARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}") + endif() -if ((NOT WIN32) AND BUILD_SHARED_LIBS) - SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBRARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}") + install(TARGETS IfcGeomServer + ARCHIVE DESTINATION ${LIBDIR} + LIBRARY DESTINATION ${LIBDIR} + RUNTIME DESTINATION ${BINDIR} + ) endif() -INSTALL(TARGETS IfcGeomServer +if(ADD_COMMIT_SHA) + find_package(Git) + + if(GIT_FOUND) + message("git found: ${GIT_EXECUTABLE} with version ${GIT_VERSION_STRING}") + execute_process( + COMMAND ${GIT_EXECUTABLE} branch --contains HEAD + OUTPUT_VARIABLE git_branches + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(REPLACE "\n" ";" git_branch_list "${git_branches}") + + foreach(git_branch_candidate IN ITEMS ${git_branch_list}) + string(STRIP "${git_branch_candidate}" git_branch_candidate_2) + + if(NOT git_branch_candidate_2 MATCHES "^HEAD$") + set(git_branch ${git_branch_candidate_2}) + endif() + endforeach() + + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD + OUTPUT_VARIABLE git_sha + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + message(STATUS "IfcOpenShell branch: \"${git_branch}\"") + message(STATUS "IfcOpenShell commit: \"${git_sha}\"") + add_definitions(-DIFCOPENSHELL_BRANCH=${git_branch}) + add_definitions(-DIFCOPENSHELL_COMMIT=${git_sha}) + endif() +endif() + +# Documentation +if(BUILD_DOCUMENTATION) + set(CMAKE_MODULE_PATH "../docs/cmake") + add_subdirectory(../docs docs) +endif() + +if(NOT MINIMAL_BUILD AND BUILD_IFCPYTHON) + add_subdirectory(../src/ifcwrap ifcwrap) +endif() + +if(BUILD_EXAMPLES) + add_subdirectory(../src/examples examples) +endif() + +if(NOT MINIMAL_BUILD AND BUILD_IFCMAX) + add_subdirectory(../src/ifcmax ifcmax) +endif() + +if(NOT MINIMAL_BUILD) + add_subdirectory(../src/svgfill svgfill) +endif() + +# CMake installation targets +install(FILES ${IFCPARSE_H_FILES} + DESTINATION ${INCLUDEDIR}/ifcparse +) + +install(TARGETS IfcParse ARCHIVE DESTINATION ${LIBDIR} LIBRARY DESTINATION ${LIBDIR} RUNTIME DESTINATION ${BINDIR} ) +<<<<<<< HEAD endif() if (ADD_COMMIT_SHA) @@ -1010,46 +1131,48 @@ INSTALL(TARGETS IfcParse RUNTIME DESTINATION ${BINDIR} ) +======= +>>>>>>> af84942e (cmake format and unify file) if(BUILD_IFCGEOM) -INSTALL(FILES ${IFCGEOM_H_FILES} - DESTINATION ${INCLUDEDIR}/ifcgeom -) + install(FILES ${IFCGEOM_H_FILES} + DESTINATION ${INCLUDEDIR}/ifcgeom + ) -INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES} - DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic -) + install(FILES ${SCHEMA_AGNOSTIC_H_FILES} + DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic + ) -INSTALL(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom - ARCHIVE DESTINATION ${LIBDIR} - LIBRARY DESTINATION ${LIBDIR} - RUNTIME DESTINATION ${BINDIR} -) + install(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom + ARCHIVE DESTINATION ${LIBDIR} + LIBRARY DESTINATION ${LIBDIR} + RUNTIME DESTINATION ${BINDIR} + ) endif() if(BUILD_CONVERT) -INSTALL(TARGETS Serializers ${SERIALIZER_SCHEMA_LIBRARIES} - ARCHIVE DESTINATION ${LIBDIR} - LIBRARY DESTINATION ${LIBDIR} - RUNTIME DESTINATION ${BINDIR} -) + install(TARGETS Serializers ${SERIALIZER_SCHEMA_LIBRARIES} + ARCHIVE DESTINATION ${LIBDIR} + LIBRARY DESTINATION ${LIBDIR} + RUNTIME DESTINATION ${BINDIR} + ) -INSTALL(FILES ${SERIALIZERS_FILES} - DESTINATION ${INCLUDEDIR}/serializers/ -) + install(FILES ${SERIALIZERS_FILES} + DESTINATION ${INCLUDEDIR}/serializers/ + ) -INSTALL(FILES ${SERIALIZERS_S_FILES} - DESTINATION ${INCLUDEDIR}/serializers/schema_dependent -) + install(FILES ${SERIALIZERS_S_FILES} + DESTINATION ${INCLUDEDIR}/serializers/schema_dependent + ) endif() IF(BUILD_QTVIEWER) - ADD_SUBDIRECTORY(../src/qtviewer qtviewer) + add_subdirectory(../src/qtviewer qtviewer) endif() list(APPEND CPACK_SOURCE_IGNORE_FILES - .git - .gitignore - ) + .git + .gitignore +) set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}${EXTRA_VERSION}") @@ -1063,11 +1186,10 @@ set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") - set(CPACK_GENERATOR "TGZ;DEB") set(CPACK_SOURCE_GENERATOR "TGZ") -FOREACH(COMPONENT IN ITEMS ${BOOST_COMPONENTS}) +foreach(COMPONENT IN ITEMS ${BOOST_COMPONENTS}) string(REPLACE "_" "-" COMP ${COMPONENT}) set(BOOST_DEPS "${BOOST_DEPS}, libboost-${COMP}-dev") endforeach(COMPONENT) @@ -1081,6 +1203,6 @@ set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") set(CPACK_DEBIAN_PACKAGE_SECTION "science") set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${EXTRA_VERSION}") set(CPACK_DEBIAN_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}") -#set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/debian/postinst") +# set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/debian/postinst") include(CPack) From 695f75f3a790af52cb61e1abb2870f41c2e08e85 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Thu, 8 Sep 2022 18:28:34 +0200 Subject: [PATCH 60/81] fix missing capitalization --- cmake/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 6129b97fd1..8cc88497c2 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -509,7 +509,7 @@ if(NOT MINIMAL_BUILD AND COLLADA_SUPPORT) find_file(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS}) - IF(COLLADASWStreamWriter_h) + if(COLLADASWStreamWriter_h) message(STATUS "OpenCOLLADA header files found") add_definitions(-DWITH_OPENCOLLADA) set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_OPENCOLLADA) @@ -1165,7 +1165,7 @@ if(BUILD_CONVERT) ) endif() -IF(BUILD_QTVIEWER) +if(BUILD_QTVIEWER) add_subdirectory(../src/qtviewer qtviewer) endif() From 9caac14014de8ee7626cf4fa1c697773c1a0fa96 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Mon, 28 Aug 2023 09:32:39 +0200 Subject: [PATCH 61/81] make 3ds SDK search optional, order cmake options # Conflicts: # cmake/CMakeLists.txt --- cmake/CMakeLists.txt | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 8cc88497c2..dbbcf56ebd 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -28,18 +28,13 @@ cmake_policy(SET CMP0074 NEW) cmake_policy(SET CMP0078 OLD) cmake_policy(SET CMP0086 NEW) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() + # use extra version to make pre-release using eg semver set(EXTRA_VERSION "-alpha.3") -foreach(max_year RANGE 2014 2030) - set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}") - - if(NOT "${max_sdk}" STREQUAL "") - message(STATUS "Autodesk 3ds Max SDK found at ${max_sdk}") - set(HAS_MAX TRUE) - endif() -endforeach() - option(MINIMAL_BUILD "The build is to make a minimal version of IFC converter from OCCT into IFC." OFF) option(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON) option(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON) @@ -70,10 +65,10 @@ endif() option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF) option(ADD_COMMIT_SHA "Add commit sha and branch in version number, warning results in many rebuilds, requires git" OFF) - -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release") -endif() +option(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF) +option(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF) +# QtViewer requires Qt5 +option(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) if(MSVC AND MSVC_PARALLEL_BUILD) add_definitions("/MP") @@ -1048,7 +1043,20 @@ if(BUILD_EXAMPLES) endif() if(NOT MINIMAL_BUILD AND BUILD_IFCMAX) - add_subdirectory(../src/ifcmax ifcmax) + foreach(max_year RANGE 2014 2030) + set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}") + + if(NOT "${max_sdk}" STREQUAL "") + message(STATUS "Autodesk 3ds Max SDK found at ${max_sdk}") + set(HAS_MAX TRUE) + endif() + endforeach() + + if(HAS_MAX) + message(STATUS "No Autodesk 3ds Max SDK found, can not build IFCMax.") + else() + add_subdirectory(../src/ifcmax ifcmax) + endif() endif() if(NOT MINIMAL_BUILD) From 562ed5908d27eb01954b4c66709fc2a86443b78b Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Tue, 13 Sep 2022 16:05:34 +0200 Subject: [PATCH 62/81] fix IFC_MAX check --- cmake/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index dbbcf56ebd..9cd9df07a1 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1052,8 +1052,8 @@ if(NOT MINIMAL_BUILD AND BUILD_IFCMAX) endif() endforeach() - if(HAS_MAX) - message(STATUS "No Autodesk 3ds Max SDK found, can not build IFCMax.") + if(NOT HAS_MAX) + message(STATUS "Autodesk 3ds Max SDK not found, is required to build IFCMax.") else() add_subdirectory(../src/ifcmax ifcmax) endif() From 76948c5156ffd9c5771a3e1479a0b97ae6f60fda Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Tue, 13 Sep 2022 16:18:06 +0200 Subject: [PATCH 63/81] add uninstall target --- cmake/CMakeLists.txt | 11 +++++++++ cmake/cmake_uninstall.cmake.in | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 cmake/cmake_uninstall.cmake.in diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 9cd9df07a1..2ecf04495c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1182,6 +1182,17 @@ list(APPEND CPACK_SOURCE_IGNORE_FILES .gitignore ) +# Cmake uninstall target +if(NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) +endif() + set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}${EXTRA_VERSION}") SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}") diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in new file mode 100644 index 0000000000..794b0f2323 --- /dev/null +++ b/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,43 @@ +# ############################################################################### +# # +# This file is part of IfcOpenShell. # +# # +# IfcOpenShell is free software: you can redistribute it and/or modify # +# it under the terms of the Lesser GNU General Public License as published by # +# the Free Software Foundation, either version 3.0 of the License, or # +# (at your option) any later version. # +# # +# IfcOpenShell is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# Lesser GNU General Public License for more details. # +# # +# You should have received a copy of the Lesser GNU General Public License # +# along with this program. If not, see . # +# # +# ############################################################################### + +if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") +endif() + +file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") + +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif() + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif() +endforeach() From 1578efe366d6ec4697e27d1a7c681a00499d0aeb Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Tue, 13 Sep 2022 16:19:03 +0200 Subject: [PATCH 64/81] refactor conditional for 3ds Max SDK --- cmake/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 2ecf04495c..3f5d9528c9 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1052,10 +1052,10 @@ if(NOT MINIMAL_BUILD AND BUILD_IFCMAX) endif() endforeach() - if(NOT HAS_MAX) - message(STATUS "Autodesk 3ds Max SDK not found, is required to build IFCMax.") - else() + if(HAS_MAX) add_subdirectory(../src/ifcmax ifcmax) + else() + message(STATUS "Autodesk 3ds Max SDK not found, is required to build IFCMax.") endif() endif() From fbfd6bc485ed5df9cdadfd7513cba5500cf098c1 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Tue, 13 Sep 2022 16:20:30 +0200 Subject: [PATCH 65/81] refactor order of unify envvars --- cmake/CMakeLists.txt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 3f5d9528c9..1e7bc9451c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -147,6 +147,8 @@ endmacro() UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR) +UNIFY_ENVVARS_AND_CACHE(BOOST_ROOT) +UNIFY_ENVVARS_AND_CACHE(BOOST_LIBRARYDIR) if(NOT MINIMAL_BUILD) UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR) @@ -158,12 +160,6 @@ if(NOT MINIMAL_BUILD) UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARIES) -endif() - -UNIFY_ENVVARS_AND_CACHE(BOOST_ROOT) -UNIFY_ENVVARS_AND_CACHE(BOOST_LIBRARYDIR) - -if(NOT MINIMAL_BUILD) UNIFY_ENVVARS_AND_CACHE(CGAL_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(CGAL_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(GMP_INCLUDE_DIR) From 43468166d271c275edac20cbf55d6ebdedf3c4cb Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Tue, 13 Sep 2022 16:34:26 +0200 Subject: [PATCH 66/81] fix format of license block --- cmake/cmake_uninstall.cmake.in | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in index 794b0f2323..04da07edd6 100644 --- a/cmake/cmake_uninstall.cmake.in +++ b/cmake/cmake_uninstall.cmake.in @@ -1,21 +1,21 @@ -# ############################################################################### -# # +################################################################################ +# # # This file is part of IfcOpenShell. # -# # +# # # IfcOpenShell is free software: you can redistribute it and/or modify # # it under the terms of the Lesser GNU General Public License as published by # # the Free Software Foundation, either version 3.0 of the License, or # # (at your option) any later version. # -# # +# # # IfcOpenShell is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # Lesser GNU General Public License for more details. # -# # +# # # You should have received a copy of the Lesser GNU General Public License # # along with this program. If not, see . # -# # -# ############################################################################### +# # +################################################################################ if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") From 2d1818592820ab9bb03828d7393b04e001e313e5 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Mon, 28 Aug 2023 10:23:16 +0200 Subject: [PATCH 67/81] cmake: fix lowercase and duplicates from rebase --- cmake/CMakeLists.txt | 254 +++++++++++++++---------------------------- 1 file changed, 87 insertions(+), 167 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 1e7bc9451c..2f16aec8ed 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -52,20 +52,16 @@ option(USE_MMAP "Adds a command line options to parse IFC files from memory mapp option(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF) option(MSVC_PARALLEL_BUILD "Multi-threaded compilation in Microsoft Visual Studio (/MP)" OFF) -OPTION(NO_WARN "Disable all warnings" OFF) -OPTION(WASM_BUILD OFF) -if(${HAS_MAX}) - option(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF) -endif() +option(NO_WARN "Disable all warnings" OFF) +option(WASM_BUILD OFF) if(${BUILD_CONVERT}) option(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF) -OPTION(USD_SUPPORT "Build IfcConvert with USD support (requires pixar's USD library)." OFF) + option(USD_SUPPORT "Build IfcConvert with USD support (requires pixar's USD library)." OFF) endif() option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF) option(ADD_COMMIT_SHA "Add commit sha and branch in version number, warning results in many rebuilds, requires git" OFF) -option(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF) option(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF) # QtViewer requires Qt5 option(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) @@ -82,8 +78,6 @@ if(NO_WARN) endif() endif() -# QtViewer requires Qt6 -OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) include(GNUInstallDirs) if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND(NOT BUILD_IFCGEOM)) @@ -178,7 +172,7 @@ endif() if(NOT MINIMAL_BUILD AND GLTF_SUPPORT AND BUILD_CONVERT) UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR) - FIND_FILE(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann) + find_file(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann) if(json_hpp) message(STATUS "JSON for Modern C++ header file found") @@ -282,14 +276,6 @@ else() endif() endif() -if (WASM_BUILD) - set(BOOST_COMPONENTS) -else() - # @todo review this, shouldn't this be all possible header-only now? - # ... or rewritten using C++17 features? - set(BOOST_COMPONENTS system program_options regex thread date_time) -endif() - if(USE_MMAP) if(MSVC) # filesystem is necessary for the utf-16 wpath @@ -301,9 +287,17 @@ if(USE_MMAP) add_definitions(-DUSE_MMAP) endif() -FIND_PACKAGE(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}") -MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}") +find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +message(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}") +message(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}") + +if (WASM_BUILD) + set(BOOST_COMPONENTS) +else() + # @todo review this, shouldn't this be all possible header-only now? + # ... or rewritten using C++17 features? + set(BOOST_COMPONENTS system program_options regex thread date_time) +endif() if(NOT MINIMAL_BUILD) # libxml2 is required for IFCXML (optional) and SVGFILL (mandatory) @@ -315,10 +309,6 @@ if(NOT MINIMAL_BUILD AND IFCXML_SUPPORT) set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_IFCXML) endif() -find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -message(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}") -message(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}") - # Usage: # set(SOME_LIRARIES foo bar) # add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" d) @@ -437,35 +427,31 @@ if(BUILD_IFCGEOM) list(APPEND OPENCASCADE_LIBRARIES ws2_32.lib) endif() -# Make sure cross-referenced symbols between static OCC libraries get -# resolved. Also add thread and rt libraries. -get_filename_component(libTKernelExt ${libTKernel} EXT) -if("${libTKernelExt}" STREQUAL ".a") - set(OCCT_STATIC ON) -endif() + # Make sure cross-referenced symbols between static OCC libraries get + # resolved. Also add thread and rt libraries. + get_filename_component(libTKernelExt ${libTKernel} EXT) + if("${libTKernelExt}" STREQUAL ".a") + set(OCCT_STATIC ON) + endif() -if(WASM_BUILD) - set(CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH_BACKUP}") -endif() - -if(OCCT_STATIC) - find_package(Threads) - - 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? - # 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(OCCT_STATIC) + find_package(Threads) + + 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? + # 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}) + endif() + + if (NOT APPLE AND NOT WIN32) + set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt") + endif() + if (NOT WIN32) + set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "dl") + endif() endif() - - if (NOT APPLE AND NOT WIN32) - set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt") - endif() - if (NOT WIN32) - set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "dl") - endif() -endif() endif(BUILD_IFCGEOM) @@ -729,7 +715,7 @@ else() endif() endif() -INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} +include_directories(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} ${JSON_INCLUDE_DIR} ${HDF5_INCLUDE_DIR} ${USD_INCLUDE_DIR} ) @@ -753,8 +739,8 @@ if(NOT SCHEMA_VERSIONS) endif() endif() -foreach(s ${SCHEMA_VERSIONS}) - add_definitions(-DHAS_SCHEMA_${s}) +foreach(schema ${SCHEMA_VERSIONS}) + add_definitions(-DHAS_SCHEMA_${schema}) endforeach() string(REPLACE ";" ")(" schema_version_seq "(${SCHEMA_VERSIONS})") @@ -815,9 +801,9 @@ if(COMPILE_SCHEMA) OUTPUT_VARIABLE COMPILED_SCHEMA_NAME) # Prevent the schema that had just been compiled from being excluded - foreach(s ${SCHEMA_VERSIONS}) - if("${COMPILED_SCHEMA_NAME}" STREQUAL "${s}") - list(REMOVE_ITEM IFC_RELEASE_NOT_USED "${s}") + foreach(schema ${SCHEMA_VERSIONS}) + if("${COMPILED_SCHEMA_NAME}" STREQUAL "${schema}") + list(REMOVE_ITEM IFC_RELEASE_NOT_USED "${schema}") endif() endforeach() endif() @@ -829,8 +815,8 @@ endif() set(IFCOPENSHELL_LIBRARIES IfcParse) if (BUILD_IFCGEOM) - foreach(s ${SCHEMA_VERSIONS}) - set(IFCGEOM_SCHEMA_LIBRARIES ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom_ifc${s}) + foreach(schema ${SCHEMA_VERSIONS}) + set(IFCGEOM_SCHEMA_LIBRARIES ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom_ifc${schema}) endforeach() if (WASM_BUILD) set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES}) @@ -838,9 +824,10 @@ if (BUILD_IFCGEOM) set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES}) endif() endif() + if (BUILD_CONVERT OR BUILD_IFCPYTHON) - foreach(s ${SCHEMA_VERSIONS}) - set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} Serializers_ifc${s}) + foreach(schema ${SCHEMA_VERSIONS}) + set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} Serializers_ifc${schema}) endforeach() set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} Serializers ${SERIALIZER_SCHEMA_LIBRARIES}) endif() @@ -849,30 +836,30 @@ endif() file(GLOB IFCPARSE_H_FILES_ALL ../src/ifcparse/*.h) file(GLOB IFCPARSE_CPP_FILES_ALL ../src/ifcparse/*.cpp) -foreach(s ${IFCPARSE_H_FILES_ALL}) - get_filename_component(p "${s}" NAME) +foreach(file ${IFCPARSE_H_FILES_ALL}) + get_filename_component(filename "${file}" NAME) - if(NOT "${p}" MATCHES "[0-9]") - list(APPEND IFCPARSE_H_FILES "${s}") + if(NOT "${filename}" MATCHES "[0-9]") + list(APPEND IFCPARSE_H_FILES "${file}") endif() endforeach() -foreach(s ${IFCPARSE_CPP_FILES_ALL}) - get_filename_component(p "${s}" NAME) +foreach(file ${IFCPARSE_CPP_FILES_ALL}) + get_filename_component(filename "${file}" NAME) - if(NOT "${p}" MATCHES "[0-9]") - list(APPEND IFCPARSE_CPP_FILES "${s}") + if(NOT "${filename}" MATCHES "[0-9]") + list(APPEND IFCPARSE_CPP_FILES "${file}") endif() endforeach() -foreach(s ${SCHEMA_VERSIONS}) +foreach(schema ${SCHEMA_VERSIONS}) list(APPEND IFCPARSE_H_FILES - ../src/ifcparse/Ifc${s}.h - ../src/ifcparse/Ifc${s}-definitions.h + ../src/ifcparse/Ifc${schema}.h + ../src/ifcparse/Ifc${schema}-definitions.h ) list(APPEND IFCPARSE_CPP_FILES - ../src/ifcparse/Ifc${s}.cpp - ../src/ifcparse/Ifc${s}-schema.cpp + ../src/ifcparse/Ifc${schema}.cpp + ../src/ifcparse/Ifc${schema}-schema.cpp ) endforeach() @@ -882,9 +869,9 @@ add_library(IfcParse ${IFCPARSE_FILES}) set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS VERSION "0.6.0" SOVERSION "0.6") if (WASM_BUILD) - TARGET_LINK_LIBRARIES(IfcParse ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES}) + target_link_libraries(IfcParse ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES}) else() - TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES}) + target_link_libraries(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES}) endif() @@ -894,11 +881,11 @@ if(BUILD_IFCGEOM) file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) -foreach(s ${SCHEMA_VERSIONS}) - add_library(IfcGeom_ifc${s} STATIC ${IFCGEOM_FILES}) - set_target_properties(IfcGeom_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s}") +foreach(schema ${SCHEMA_VERSIONS}) + add_library(IfcGeom_ifc${schema} STATIC ${IFCGEOM_FILES}) + set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s}") if (NOT WASM_BUILD) - TARGET_LINK_LIBRARIES(IfcGeom_ifc${s} IfcParse ${OPENCASCADE_LIBRARIES}) + target_link_libraries(IfcGeom_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) endif() endforeach() @@ -915,9 +902,9 @@ endforeach() endif() if (WASM_BUILD) - TARGET_LINK_LIBRARIES(IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries(IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) else() - TARGET_LINK_LIBRARIES(IfcGeom IfcParse ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries(IfcGeom IfcParse ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) endif() endif(BUILD_IFCGEOM) @@ -931,21 +918,21 @@ if(BUILD_CONVERT OR BUILD_IFCPYTHON) file(GLOB SERIALIZERS_S_CPP_FILES ../src/serializers/schema_dependent/*.cpp) set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES}) -foreach(s ${SCHEMA_VERSIONS}) - add_library(Serializers_ifc${s} STATIC ${SERIALIZERS_S_FILES}) - set_target_properties(Serializers_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s} ${CONVERT_PRECISION}") +foreach(schema ${SCHEMA_VERSIONS}) + add_library(Serializers_ifc${schema} STATIC ${SERIALIZERS_S_FILES}) + set_target_properties(Serializers_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s} ${CONVERT_PRECISION}") if (WASM_BUILD) - TARGET_LINK_LIBRARIES(Serializers_ifc${s} ${HDF5_LIBRARIES}) + target_link_libraries(Serializers_ifc${schema} ${HDF5_LIBRARIES}) else() - TARGET_LINK_LIBRARIES(Serializers_ifc${s} IfcGeom ${OPENCASCADE_LIBRARIES} ${HDF5_LIBRARIES}) + target_link_libraries(Serializers_ifc${schema} IfcGeom ${OPENCASCADE_LIBRARIES} ${HDF5_LIBRARIES}) endif() endforeach() add_library(Serializers ${SERIALIZERS_FILES}) set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}" VERSION "0.6.0" SOVERSION "0.6") -TARGET_LINK_LIBRARIES(Serializers ${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES}) + target_link_libraries(Serializers ${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES}) endif(BUILD_CONVERT OR BUILD_IFCPYTHON) @@ -957,7 +944,7 @@ if(BUILD_CONVERT) add_executable(IfcConvert ${IFCCONVERT_FILES}) set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}") -TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${HDF5_LIBRARIES} ${USD_LIBRARIES}) + target_link_libraries(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${HDF5_LIBRARIES} ${USD_LIBRARIES}) if((NOT WIN32) AND BUILD_SHARED_LIBS) # Only set RPATHs when building shared libraries (i.e. IfcParse and @@ -1059,84 +1046,21 @@ if(NOT MINIMAL_BUILD) add_subdirectory(../src/svgfill svgfill) endif() +if(BUILD_QTVIEWER) + add_subdirectory(../src/qtviewer qtviewer) +endif() + # CMake installation targets install(FILES ${IFCPARSE_H_FILES} - DESTINATION ${INCLUDEDIR}/ifcparse -) - -install(TARGETS IfcParse - ARCHIVE DESTINATION ${LIBDIR} - LIBRARY DESTINATION ${LIBDIR} - RUNTIME DESTINATION ${BINDIR} -) - -<<<<<<< HEAD -endif() - -if (ADD_COMMIT_SHA) -find_package (Git) -if (GIT_FOUND) - message("git found: ${GIT_EXECUTABLE} with version ${GIT_VERSION_STRING}") - execute_process( - COMMAND ${GIT_EXECUTABLE} branch -a --contains HEAD - OUTPUT_VARIABLE git_branches - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - string(REPLACE "\n" ";" git_branch_list "${git_branches}") - foreach(git_branch_candidate IN ITEMS ${git_branch_list}) - string(REPLACE "*" "" git_branch_candidate_temp "${git_branch_candidate}") - string(STRIP "${git_branch_candidate_temp}" git_branch_candidate_2) - if (NOT git_branch_candidate_2 MATCHES "^HEAD$") - string(REPLACE "/" ";" git_branch_candidate_2_list "${git_branch_candidate_2}") - list(GET git_branch_candidate_2_list -1 git_branch) - endif() - endforeach() - execute_process( - COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD - OUTPUT_VARIABLE git_sha - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - message(STATUS "IfcOpenShell branch: \"${git_branch}\"") - message(STATUS "IfcOpenShell commit: \"${git_sha}\"") - add_definitions(-DIFCOPENSHELL_BRANCH=${git_branch}) - add_definitions(-DIFCOPENSHELL_COMMIT=${git_sha}) -endif() -endif() - -# Documentation -IF(BUILD_DOCUMENTATION) - set(CMAKE_MODULE_PATH "../docs/cmake") - ADD_SUBDIRECTORY(../docs docs) -ENDIF() - -IF(NOT MINIMAL_BUILD AND BUILD_IFCPYTHON) - ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap) -ENDIF() - -IF(BUILD_EXAMPLES) - ADD_SUBDIRECTORY(../src/examples examples) -ENDIF() - -IF(NOT MINIMAL_BUILD AND BUILD_IFCMAX) - ADD_SUBDIRECTORY(../src/ifcmax ifcmax) -ENDIF() -if (NOT MINIMAL_BUILD) -ADD_SUBDIRECTORY(../src/svgfill svgfill) -endif() - -# CMake installation targets -INSTALL(FILES ${IFCPARSE_H_FILES} DESTINATION ${INCLUDEDIR}/ifcparse ) -INSTALL(TARGETS IfcParse +install(TARGETS IfcParse ARCHIVE DESTINATION ${LIBDIR} LIBRARY DESTINATION ${LIBDIR} RUNTIME DESTINATION ${BINDIR} ) -======= ->>>>>>> af84942e (cmake format and unify file) if(BUILD_IFCGEOM) install(FILES ${IFCGEOM_H_FILES} DESTINATION ${INCLUDEDIR}/ifcgeom @@ -1169,15 +1093,6 @@ if(BUILD_CONVERT) ) endif() -if(BUILD_QTVIEWER) - add_subdirectory(../src/qtviewer qtviewer) -endif() - -list(APPEND CPACK_SOURCE_IGNORE_FILES - .git - .gitignore -) - # Cmake uninstall target if(NOT TARGET uninstall) configure_file( @@ -1189,6 +1104,11 @@ if(NOT TARGET uninstall) COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) endif() +# Packaging +list(APPEND CPACK_SOURCE_IGNORE_FILES + .git + .gitignore +) set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}${EXTRA_VERSION}") SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}") From 764c818d10f9d802b6d8c59a799e30b20dbd6093 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Mon, 28 Aug 2023 10:48:59 +0200 Subject: [PATCH 68/81] cmake: fix inline variable error --- cmake/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 2f16aec8ed..f2f46cb08f 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -883,7 +883,7 @@ if(BUILD_IFCGEOM) foreach(schema ${SCHEMA_VERSIONS}) add_library(IfcGeom_ifc${schema} STATIC ${IFCGEOM_FILES}) - set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s}") + set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}") if (NOT WASM_BUILD) target_link_libraries(IfcGeom_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) endif() @@ -920,7 +920,7 @@ if(BUILD_CONVERT OR BUILD_IFCPYTHON) foreach(schema ${SCHEMA_VERSIONS}) add_library(Serializers_ifc${schema} STATIC ${SERIALIZERS_S_FILES}) - set_target_properties(Serializers_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s} ${CONVERT_PRECISION}") + set_target_properties(Serializers_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} ${CONVERT_PRECISION}") if (WASM_BUILD) target_link_libraries(Serializers_ifc${schema} ${HDF5_LIBRARIES}) From 2bb64a6cae49c673c3b12b8a530e471d1a72e6b3 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Mon, 28 Aug 2023 14:50:58 +0200 Subject: [PATCH 69/81] cmake: fix order to set boost components --- cmake/CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index f2f46cb08f..5dcb060d8c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -276,6 +276,14 @@ else() endif() endif() +if (WASM_BUILD) + set(BOOST_COMPONENTS) +else() + # @todo review this, shouldn't this be all possible header-only now? + # ... or rewritten using C++17 features? + set(BOOST_COMPONENTS system program_options regex thread date_time) +endif() + if(USE_MMAP) if(MSVC) # filesystem is necessary for the utf-16 wpath @@ -291,14 +299,6 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) message(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}") message(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}") -if (WASM_BUILD) - set(BOOST_COMPONENTS) -else() - # @todo review this, shouldn't this be all possible header-only now? - # ... or rewritten using C++17 features? - set(BOOST_COMPONENTS system program_options regex thread date_time) -endif() - if(NOT MINIMAL_BUILD) # libxml2 is required for IFCXML (optional) and SVGFILL (mandatory) find_package(LibXml2 REQUIRED) From a3ecde3ad90b0e18c958e53348023d52a5f407c2 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Wed, 30 Aug 2023 11:49:48 +0200 Subject: [PATCH 70/81] cmake: reset wrong fix on merge conflict --- cmake/CMakeLists.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 5dcb060d8c..88ff243e36 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -985,17 +985,18 @@ if(ADD_COMMIT_SHA) if(GIT_FOUND) message("git found: ${GIT_EXECUTABLE} with version ${GIT_VERSION_STRING}") execute_process( - COMMAND ${GIT_EXECUTABLE} branch --contains HEAD + COMMAND ${GIT_EXECUTABLE} branch -a --contains HEAD OUTPUT_VARIABLE git_branches OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REPLACE "\n" ";" git_branch_list "${git_branches}") foreach(git_branch_candidate IN ITEMS ${git_branch_list}) - string(STRIP "${git_branch_candidate}" git_branch_candidate_2) - - if(NOT git_branch_candidate_2 MATCHES "^HEAD$") - set(git_branch ${git_branch_candidate_2}) + string(REPLACE "*" "" git_branch_candidate_temp "${git_branch_candidate}") + string(STRIP "${git_branch_candidate_temp}" git_branch_candidate_2) + if (NOT git_branch_candidate_2 MATCHES "^HEAD$") + string(REPLACE "/" ";" git_branch_candidate_2_list "${git_branch_candidate_2}") + list(GET git_branch_candidate_2_list -1 git_branch) endif() endforeach() From e6d48cd37fcc3253e856c4b50b4ea6312a040d25 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Thu, 31 Aug 2023 11:25:59 +0200 Subject: [PATCH 71/81] cmake: fix reset to ROOT_PATH back in --- cmake/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 88ff243e36..57e7424287 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -617,6 +617,11 @@ if(NOT MINIMAL_BUILD AND HDF5_SUPPORT) set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_HDF5) endif() +if(WASM_BUILD) + # reset to use sysroot + set(CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH_BACKUP}") +endif() + if(ENABLE_BUILD_OPTIMIZATIONS) if(MSVC) # NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default, From 5c78e298494fde3cbc0a63214a67a769457afbf3 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Thu, 31 Aug 2023 11:37:17 +0200 Subject: [PATCH 72/81] cmake: fix target versions closes #3671 --- cmake/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 57e7424287..c5ae5c1e98 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -871,7 +871,7 @@ endforeach() set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES}) add_library(IfcParse ${IFCPARSE_FILES}) -set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS VERSION "0.6.0" SOVERSION "0.6") +set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") if (WASM_BUILD) target_link_libraries(IfcParse ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES}) @@ -900,7 +900,7 @@ endforeach() set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES}) - set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS VERSION "0.6.0" SOVERSION "0.6") + set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") if(UNIX) find_package(Threads) @@ -935,7 +935,7 @@ foreach(schema ${SCHEMA_VERSIONS}) endforeach() add_library(Serializers ${SERIALIZERS_FILES}) - set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}" VERSION "0.6.0" SOVERSION "0.6") + set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}" VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") target_link_libraries(Serializers ${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES}) From 83dda3e73fe9432b31bf929f011edcc855fb4c20 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Thu, 31 Aug 2023 11:48:14 +0200 Subject: [PATCH 73/81] cmake: fix QT version number from merge conflict --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index c5ae5c1e98..a1a4d87dcf 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -63,7 +63,7 @@ endif() option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF) option(ADD_COMMIT_SHA "Add commit sha and branch in version number, warning results in many rebuilds, requires git" OFF) option(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF) -# QtViewer requires Qt5 +# QtViewer requires Qt6 option(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) if(MSVC AND MSVC_PARALLEL_BUILD) From 726c792fbed403767759837019b79bee7ab41142 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Thu, 31 Aug 2023 12:32:23 +0200 Subject: [PATCH 74/81] cmake: remove unused CONVERT_PRECISION closes #3672 --- cmake/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a1a4d87dcf..2c83e2bd2a 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -925,7 +925,7 @@ if(BUILD_CONVERT OR BUILD_IFCPYTHON) foreach(schema ${SCHEMA_VERSIONS}) add_library(Serializers_ifc${schema} STATIC ${SERIALIZERS_S_FILES}) - set_target_properties(Serializers_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} ${CONVERT_PRECISION}") + set_target_properties(Serializers_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}") if (WASM_BUILD) target_link_libraries(Serializers_ifc${schema} ${HDF5_LIBRARIES}) @@ -935,7 +935,7 @@ foreach(schema ${SCHEMA_VERSIONS}) endforeach() add_library(Serializers ${SERIALIZERS_FILES}) - set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}" VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") + set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS" VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") target_link_libraries(Serializers ${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES}) @@ -947,7 +947,6 @@ if(BUILD_CONVERT) file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h) set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES}) add_executable(IfcConvert ${IFCCONVERT_FILES}) - set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}") target_link_libraries(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${HDF5_LIBRARIES} ${USD_LIBRARIES}) From 8d450aa5008be4eba8cc856f96cca127e57c8576 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 1 Sep 2023 22:13:50 +1000 Subject: [PATCH 75/81] Fix #3470. Fix bug where hppfcl for IfcClash was incorrectly bundled for Windows. --- src/blenderbim/Makefile | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/blenderbim/Makefile b/src/blenderbim/Makefile index b5b39c73ed..736a2277a1 100644 --- a/src/blenderbim/Makefile +++ b/src/blenderbim/Makefile @@ -57,7 +57,6 @@ ifeq ($(PYVERSION), py39) HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/linux-64/hpp-fcl-2.3.4-py39h40a70d0_0.conda EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/linux-64/eigenpy-3.1.0-py39hdfdd6bb_0.conda BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py39h7c9e3ff_4.tar.bz2 -QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/linux-64/qhull-2020.2-h4bd325d_2.tar.bz2 LXML_URL:=https://files.pythonhosted.org/packages/19/d9/a69c6aff5673554df48120565a14a50eaa41d29ae03b02faa0b023666318/lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl SHAPELY_URL:=https://files.pythonhosted.org/packages/2d/f2/8ec281d357e8bb7d08dc8d727f0e4c8ef3dae7d3fa75c69c8e452bb82d50/shapely-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl PILLOW_URL:=https://files.pythonhosted.org/packages/01/61/3ff85fb4bb596ce3d223c8fcf93c8df5c12bc8899dfb4fb3cb1c5b20dd5f/Pillow-9.2.0-cp39-cp39-manylinux_2_28_x86_64.whl @@ -66,12 +65,12 @@ ifeq ($(PYVERSION), py310) HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/linux-64/hpp-fcl-2.3.4-py310h995690b_0.conda EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/linux-64/eigenpy-3.1.0-py310hf02b7e0_0.conda BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py310hc4a4660_4.tar.bz2 -QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/linux-64/qhull-2020.2-h4bd325d_2.tar.bz2 LXML_URL:=https://files.pythonhosted.org/packages/25/1e/19b46d8e8881fe0df2e20945d51919eeb1817836d62a90efa8506530e45c/lxml-4.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl SHAPELY_URL:=https://files.pythonhosted.org/packages/a8/a5/403728b5614b28083f6424dfdefec5fcf58068495fb03bb08532671c642f/shapely-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl PILLOW_URL:=https://files.pythonhosted.org/packages/f6/51/320986ebd6d46a0e95c2240468ced73153b691ce07617078bcdf30c609ec/Pillow-9.2.0-cp310-cp310-manylinux_2_28_x86_64.whl endif ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/linux-64/assimp-5.0.1-hedfc422_6.tar.bz2 +QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/linux-64/qhull-2020.2-h4bd325d_2.tar.bz2 OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.8/download/linux-64/octomap-1.9.8-h924138e_0.tar.bz2 BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/linux-64/boost-cpp-1.78.0-h6582d0a_3.conda ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/linux-64/zlib-1.2.11-h516909a_1010.tar.bz2 @@ -83,7 +82,6 @@ ifeq ($(PYVERSION), py39) HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-64/hpp-fcl-2.3.4-py39hd85b194_0.conda EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-64/eigenpy-3.1.0-py39hc4d6e28_0.conda BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py39h953a6b8_4.tar.bz2 -QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-64/qhull-2020.2-h940c156_2.tar.bz2 LXML_URL:=https://files.pythonhosted.org/packages/b8/74/a71f7ad72e8db54ce899efab84507b801660750cbbfa6a39e6717557d36a/lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl SHAPELY_URL:=https://files.pythonhosted.org/packages/36/a4/7e542a209f862f967d7cb8e939eff155f4294a27d17e16441fb8bdd51a2c/shapely-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl PILLOW_URL:=https://files.pythonhosted.org/packages/88/7a/ddfe28b485b623361457d4783007c1f9ba83a87f93e7fec32f64793efb6c/Pillow-9.2.0-cp39-cp39-macosx_10_10_x86_64.whl @@ -92,12 +90,12 @@ ifeq ($(PYVERSION), py310) HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-64/hpp-fcl-2.3.4-py310h1db6f5f_0.conda EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-64/eigenpy-3.1.0-py310h43da829_0.conda BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py310h3e792ce_4.tar.bz2 -QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-64/qhull-2020.2-h940c156_2.tar.bz2 LXML_URL:=https://files.pythonhosted.org/packages/a1/44/17b7dac7a18807d30e2fe10c3328c152808f5464565e230bfd0e77f178c6/lxml-4.8.0-cp310-cp310-macosx_10_15_x86_64.whl SHAPELY_URL:=https://files.pythonhosted.org/packages/1f/2a/dc3353c2431cf53e8d04bb8fba27e584410ca3435c9c85f76d71bf0c0e80/shapely-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl PILLOW_URL:=https://files.pythonhosted.org/packages/d8/60/b13c00d403f34110e96c1b5c0afa73ce461efe3fe960c3a7e3e7fe190d82/Pillow-9.2.0-cp310-cp310-macosx_10_10_x86_64.whl 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 OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.8/download/osx-64/octomap-1.9.8-hb8565cd_0.tar.bz2 BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/osx-64/boost-cpp-1.78.0-hf5ba120_3.conda ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/osx-64/zlib-1.2.11-h7795811_1010.tar.bz2 @@ -109,7 +107,6 @@ ifeq ($(PYVERSION), py39) HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-arm64/hpp-fcl-2.3.4-py39hc34188a_0.conda EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-arm64/eigenpy-3.1.0-py39h13cfc01_0.conda BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py39h99de9ae_4.tar.bz2 -QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-arm64/qhull-2020.2-hc021e02_2.tar.bz2 LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py39h9eb174b_0.tar.bz2 SHAPELY_URL:=https://files.pythonhosted.org/packages/ea/aa/45fbd031edf3149cb767d8b9f9db45d5faf0324d743c6b8fb0298cc022d0/shapely-2.0.1-cp39-cp39-macosx_11_0_arm64.whl PILLOW_URL:=https://files.pythonhosted.org/packages/aa/bc/21097cd891dd2fa02f2b3d767e02e883e026482e59d29975d1bc30024aa3/Pillow-9.2.0-cp39-cp39-macosx_11_0_arm64.whl @@ -118,12 +115,12 @@ ifeq ($(PYVERSION), py310) HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-arm64/hpp-fcl-2.3.4-py310h46fc4cd_0.conda EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-arm64/eigenpy-3.1.0-py310ha2643af_0.conda BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py310h629746b_4.tar.bz2 -QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-arm64/qhull-2020.2-hc021e02_2.tar.bz2 LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py310h02f21da_0.tar.bz2 SHAPELY_URL:=https://files.pythonhosted.org/packages/ec/41/d59208743e737184e1b403e95a937aebb022b8459e99efbcd5208fc8be46/shapely-2.0.1-cp310-cp310-macosx_11_0_arm64.whl PILLOW_URL:=https://files.pythonhosted.org/packages/0c/5f/117b653cad585f3aedfe0de996c292e67d4b020ed77f652e5a6c8c24f908/Pillow-9.2.0-cp310-cp310-macosx_11_0_arm64.whl endif ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/osx-arm64/assimp-5.0.1-h0f81e16_7.tar.bz2 +QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-arm64/qhull-2020.2-hc021e02_2.tar.bz2 OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.8/download/osx-arm64/octomap-1.9.8-hffc8910_0.tar.bz2 BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/osx-arm64/boost-cpp-1.78.0-h9ed8d21_3.conda ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/osx-arm64/zlib-1.2.11-h90dfc92_1014.tar.bz2 @@ -147,7 +144,8 @@ LXML_URL:=https://files.pythonhosted.org/packages/f6/71/65c80a4caa1617a4c6e8fe15 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 -ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/win-64/assimp-5.0.1-hc2aa0de_6.tar.bz2 +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 OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.8/download/win-64/octomap-1.9.8-h91493d7_0.tar.bz2 BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/win-64/boost-cpp-1.78.0-h9f4b32c_3.conda ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/win-64/zlib-1.2.11-h62dcd97_1010.tar.bz2 @@ -437,8 +435,7 @@ ifeq ($(PLATFORM), win) endif rm -rf dist/working - # Required by hpp-fcl except on Windows -ifneq ($(PLATFORM), win) + # Required by hpp-fcl mkdir dist/working cd dist/working && wget $(QHULL_URL) cd dist/working && tar -xf qhull* @@ -451,8 +448,10 @@ endif ifeq ($(PLATFORM), macosm1) cp -r dist/working/lib/*.dylib dist/blenderbim/libs/ endif - rm -rf dist/working +ifeq ($(PLATFORM), win) + cp -r dist/working/Library/bin/*.dll dist/blenderbim/libs/site/packages/hppfcl/ endif + rm -rf dist/working # Required by hpp-fcl mkdir dist/working @@ -487,7 +486,7 @@ ifeq ($(PLATFORM), macosm1) cp -r dist/working/lib/*.dylib dist/blenderbim/libs/ endif ifeq ($(PLATFORM), win) - # Uh, do nothing, apparently? No DLLs are shipped. + cp -r dist/working/Library/bin/*.dll dist/blenderbim/libs/site/packages/hppfcl/ endif rm -rf dist/working From c07371cb76b6b370ec57184a58d9cca753e8b9a5 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 1 Sep 2023 10:58:18 +0500 Subject: [PATCH 76/81] couple descriptions for setting north --- .../blenderbim/bim/module/georeference/operator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/georeference/operator.py b/src/blenderbim/blenderbim/bim/module/georeference/operator.py index eec2dab9ca..ed6d96d7d8 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/operator.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/operator.py @@ -76,7 +76,7 @@ class SetIfcGridNorth(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.set_ifc_grid_north" bl_label = "Set IFC Grid North" bl_options = {"REGISTER", "UNDO"} - bl_description = "Set IFC grid north" + bl_description = "Set IFC grid north based on current Blender North Offset" def _execute(self, context): core.set_ifc_grid_north(tool.Georeference) @@ -86,7 +86,7 @@ class SetBlenderGridNorth(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.set_blender_grid_north" bl_label = "Set Blender Grid North" bl_options = {"REGISTER", "UNDO"} - bl_description = "Set Blender grid north" + bl_description = "Set Blender North Offset based on current IFC grid north" def _execute(self, context): core.set_blender_grid_north(tool.Georeference) @@ -125,7 +125,7 @@ class SetIfcTrueNorth(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.set_ifc_true_north" bl_label = "Set IFC True North" bl_options = {"REGISTER", "UNDO"} - bl_description = "Set IFC True north" + bl_description = "Set IFC true north based on current Blender North Offset" def _execute(self, context): core.set_ifc_true_north(tool.Georeference) @@ -135,7 +135,7 @@ class SetBlenderTrueNorth(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.set_blender_true_north" bl_label = "Set Blender True North" bl_options = {"REGISTER", "UNDO"} - bl_description = "Set Blender true north" + bl_description = "Set Blender North Offset based on current IFC true north" def _execute(self, context): core.set_blender_true_north(tool.Georeference) From e48a3a06c06e9aa33b2981e772bfdda38cf0e31a Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 1 Sep 2023 18:24:02 +0500 Subject: [PATCH 77/81] Fixed bug with adding obstruction fittings --- src/blenderbim/blenderbim/bim/module/model/mep.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/mep.py b/src/blenderbim/blenderbim/bim/module/model/mep.py index 75681f9166..e6aaa734da 100644 --- a/src/blenderbim/blenderbim/bim/module/model/mep.py +++ b/src/blenderbim/blenderbim/bim/module/model/mep.py @@ -402,15 +402,23 @@ class MEPGenerator: return len(segments_data) == 0 def pack_return_data(fitting_type, ports, segments_data): + packed_data = {"fitting_type": fitting_type} + + if predefined_type == "OBSTRUCTION": + return packed_data + for port in ports: port_local_position = V(*port.ObjectPlacement.RelativePlacement.Location.Coordinates) if tool.Cad.is_x(port_local_position.length, 0.0): start_port = port break + connected_port = tool.System.get_connected_port(start_port) connected_element = tool.System.get_port_relating_element(connected_port) element_type = ifcopenshell.util.element.get_type(connected_element) - return {"fitting_type": fitting_type, "start_port_match": element_type == segments_data[0][0]} + packed_data["start_port_match"] = element_type == segments_data[0][0] + + return packed_data fitting_types = tool.Ifc.get().by_type(self.get_mep_element_class_name(segments[0], "FittingType")) for fitting_type in fitting_types: From f2097b9036bfb40fa0ee860b981cdc94bb619381 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Fri, 1 Sep 2023 16:58:56 +0200 Subject: [PATCH 78/81] cmake: fix PATHS syntax error closes #2632 --- cmake/CMakeLists.txt | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 2c83e2bd2a..0f428738bf 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -191,10 +191,9 @@ if(NOT MINIMAL_BUILD AND USD_SUPPORT) if("${USD_INCLUDE_DIR}" STREQUAL "") find_path(USD_INCLUDE_DIR pxr.h - [PATHS + PATHS /usr/include/pxr /usr/local/include/pxr - ] REQUIRED ) if(USD_INCLUDE_DIR) @@ -355,11 +354,10 @@ if(BUILD_IFCGEOM) # Open CASCADE if("${OCC_INCLUDE_DIR}" STREQUAL "") find_path(OCC_INCLUDE_DIR Standard_Version.hxx - [PATHS - /usr/include/occt - /usr/include/oce - /usr/include/opencascade - ] + PATHS + /usr/include/occt + /usr/include/oce + /usr/include/opencascade REQUIRED ) @@ -383,9 +381,8 @@ if(BUILD_IFCGEOM) if("${OCC_LIBRARY_DIR}" STREQUAL "") find_library(OCC_LIBRARY TKernel - [PATHS - /usr/lib - ] + PATHS + /usr/lib REQUIRED ) From 294935ceed8f0d538fdfa2cc74c02af89463e1d7 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 2 Sep 2023 16:29:22 +1000 Subject: [PATCH 79/81] See #3682. You can now add symbols and multisymbols (i.e. one vertex per symbol) annotations. New default symbols for setout points in demo library. --- .../blenderbim/bim/data/assets/symbols.svg | 15 +- .../bim/data/libraries/IFC4 Demo Library.ifc | 335 +++++++++--------- .../bim/module/drawing/annotation.py | 11 + .../blenderbim/bim/module/drawing/prop.py | 2 + .../bim/module/drawing/svgwriter.py | 44 ++- src/blenderbim/blenderbim/tool/drawing.py | 2 + .../scripts/generate_demo_library.py | 9 + .../api/geometry/add_representation.py | 2 + 8 files changed, 242 insertions(+), 178 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/data/assets/symbols.svg b/src/blenderbim/blenderbim/bim/data/assets/symbols.svg index 7011554551..5aca6a35eb 100644 --- a/src/blenderbim/blenderbim/bim/data/assets/symbols.svg +++ b/src/blenderbim/blenderbim/bim/data/assets/symbols.svg @@ -44,17 +44,22 @@ - + - - + + + + + + + - + - + diff --git a/src/blenderbim/blenderbim/bim/data/libraries/IFC4 Demo Library.ifc b/src/blenderbim/blenderbim/bim/data/libraries/IFC4 Demo Library.ifc index a86680bbd0..190b13d9a4 100644 --- a/src/blenderbim/blenderbim/bim/data/libraries/IFC4 Demo Library.ifc +++ b/src/blenderbim/blenderbim/bim/data/libraries/IFC4 Demo Library.ifc @@ -1,13 +1,13 @@ ISO-10303-21; HEADER; FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1'); -FILE_NAME('/dev/null','2023-07-30T21:07:33+10:00',(),(),'IfcOpenShell v0.7.0-8f41ae0c1','IfcOpenShell v0.7.0-8f41ae0c1','Nobody'); +FILE_NAME('/dev/null','2023-09-02T16:09:02+10:00',(),(),'IfcOpenShell v0.7.0-fbd8ea1ed','IfcOpenShell v0.7.0-fbd8ea1ed','Nobody'); FILE_SCHEMA(('IFC4')); ENDSEC; DATA; -#1=IFCPROJECT('0TszJmTqLCyxcP10DtK_MP',$,'BlenderBIM Demo',$,$,$,$,(#12,#16),#7); -#2=IFCPROJECTLIBRARY('0Y_CJXSsbCgBlSGFw0mbLa',$,'BlenderBIM Demo Library',$,$,$,$,$,$); -#3=IFCRELDECLARES('3IxQaOPH5Fx90CGmGm1gtQ',$,$,$,#1,(#2)); +#1=IFCPROJECT('1UlLTVwDzDvR$QNEAxFx6F',$,'BlenderBIM Demo',$,$,$,$,(#12,#16),#7); +#2=IFCPROJECTLIBRARY('3QN02XEh1FQh0fii364VEi',$,'BlenderBIM Demo Library',$,$,$,$,$,$); +#3=IFCRELDECLARES('0aiEyU5lL7mAdB5xwdXbUN',$,$,$,#1,(#2)); #4=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); #5=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); #6=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.); @@ -25,82 +25,82 @@ DATA; #18=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Plan',*,*,*,*,#16,$,.PLAN_VIEW.,$); #19=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#16,$,.PLAN_VIEW.,$); #20=IFCMATERIAL('Unknown',$,$); -#21=IFCWALLTYPE('3U0gAUglf9WBlcfpB15EK0',$,'WAL50',$,$,$,$,$,$,.NOTDEFINED.); +#21=IFCWALLTYPE('0Ir6HewafB2hnPRigxrUnM',$,'WAL50',$,$,$,$,$,$,.NOTDEFINED.); #22=IFCMATERIALLAYERSET((#24),$,$); -#23=IFCRELASSOCIATESMATERIAL('3J36H22Gz1ovVzdiKgApaM',$,$,$,(#21),#22); +#23=IFCRELASSOCIATESMATERIAL('3S$YbWQCnDCA2tmoikSnrh',$,$,$,(#21),#22); #24=IFCMATERIALLAYER(#20,0.05,$,$,$,$,$); -#25=IFCRELDECLARES('28ApgMJzH10h$Ng$fmCpYf',$,$,$,#2,(#63,#21,#54,#87,#153,#34,#67,#210,#38,#82,#77,#42,#26,#48,#72,#59,#92,#30,#96)); -#26=IFCWALLTYPE('1wGfdUdC10TuASJo4jnO99',$,'WAL100',$,$,$,$,$,$,.NOTDEFINED.); +#25=IFCRELDECLARES('1eLCJqssP2kvQIdmPlRK19',$,$,$,#2,(#38,#82,#77,#42,#26,#48,#72,#59,#92,#30,#96,#63,#54,#87,#153,#34,#67,#21,#210)); +#26=IFCWALLTYPE('2oUFJayonDlBTcbJtxYFSv',$,'WAL100',$,$,$,$,$,$,.NOTDEFINED.); #27=IFCMATERIALLAYERSET((#29),$,$); -#28=IFCRELASSOCIATESMATERIAL('0NRoxSQPzCgQHfsu5ru91z',$,$,$,(#26),#27); +#28=IFCRELASSOCIATESMATERIAL('0n3vPKxufDgO48f4yfGtUd',$,$,$,(#26),#27); #29=IFCMATERIALLAYER(#20,0.1,$,$,$,$,$); -#30=IFCWALLTYPE('1lt5MuGLLDfwmZd0tNruF7',$,'WAL200',$,$,$,$,$,$,.NOTDEFINED.); +#30=IFCWALLTYPE('0UDhWxnIXDMOxZ2yPDCUMP',$,'WAL200',$,$,$,$,$,$,.NOTDEFINED.); #31=IFCMATERIALLAYERSET((#33),$,$); -#32=IFCRELASSOCIATESMATERIAL('21rGVxPODC$xmWYFaDy1T6',$,$,$,(#30),#31); +#32=IFCRELASSOCIATESMATERIAL('2Boxz3uaP0LOy6luKau2R0',$,$,$,(#30),#31); #33=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$); -#34=IFCWALLTYPE('0NZm1D8h12xAxyW7fL5nc1',$,'WAL300',$,$,$,$,$,$,.NOTDEFINED.); +#34=IFCWALLTYPE('20fPutWQrFyeMIiKxc$MkU',$,'WAL300',$,$,$,$,$,$,.NOTDEFINED.); #35=IFCMATERIALLAYERSET((#37),$,$); -#36=IFCRELASSOCIATESMATERIAL('2yvmN42crCJevtirp5cMeV',$,$,$,(#34),#35); +#36=IFCRELASSOCIATESMATERIAL('2qAjlTTxjBkvdp80A9XdMZ',$,$,$,(#34),#35); #37=IFCMATERIALLAYER(#20,0.3,$,$,$,$,$); -#38=IFCCOVERINGTYPE('1eb4wZ_5n6xRGrs3rlKMiM',$,'COV10',$,$,$,$,$,$,.NOTDEFINED.); +#38=IFCCOVERINGTYPE('100hdtcxzBdQATomAi0tv5',$,'COV10',$,$,$,$,$,$,.NOTDEFINED.); #39=IFCMATERIALLAYERSET((#41),$,$); -#40=IFCRELASSOCIATESMATERIAL('3HKIKf06T6xRqM6Lp69$OM',$,$,$,(#38),#39); +#40=IFCRELASSOCIATESMATERIAL('3tO1xRn9b06utMa1TZC$WW',$,$,$,(#38),#39); #41=IFCMATERIALLAYER(#20,0.01,$,$,$,$,$); -#42=IFCCOVERINGTYPE('2E89aYmtrEfxhX_jsNqviN',$,'COV20',$,$,(#46),$,$,$,.NOTDEFINED.); +#42=IFCCOVERINGTYPE('1sO51oul95ABWezHr7P7Dk',$,'COV20',$,$,(#46),$,$,$,.NOTDEFINED.); #43=IFCMATERIALLAYERSET((#45),$,$); -#44=IFCRELASSOCIATESMATERIAL('2115lEhhP4Z9G1Yhd_DqSC',$,$,$,(#42),#43); +#44=IFCRELASSOCIATESMATERIAL('0w6lexCg19TuiqqTxo91zc',$,$,$,(#42),#43); #45=IFCMATERIALLAYER(#20,0.02,$,$,$,$,$); -#46=IFCPROPERTYSET('0vtU63YmjAgg8DeHlTgNx7',$,'EPset_Parametric',$,(#47)); +#46=IFCPROPERTYSET('3ytgFxH0571uBCG4mBNXI9',$,'EPset_Parametric',$,(#47)); #47=IFCPROPERTYSINGLEVALUE('LayerSetDirection',$,IFCLABEL('AXIS2'),$); -#48=IFCCOVERINGTYPE('0XiSBI57L9Uf8f2NaQ_ksi',$,'COV30',$,$,(#52),$,$,$,.NOTDEFINED.); +#48=IFCCOVERINGTYPE('09GKC1aO56qwEPF9halcxJ',$,'COV30',$,$,(#52),$,$,$,.NOTDEFINED.); #49=IFCMATERIALLAYERSET((#51),$,$); -#50=IFCRELASSOCIATESMATERIAL('3U3JdGAmbABA4mB$Fgpq1l',$,$,$,(#48),#49); +#50=IFCRELASSOCIATESMATERIAL('0rDrnpiX58DgQhcURj_WlB',$,$,$,(#48),#49); #51=IFCMATERIALLAYER(#20,0.03,$,$,$,$,$); -#52=IFCPROPERTYSET('17nhQ5I4b9ZvhDu4gRJLKO',$,'EPset_Parametric',$,(#53)); +#52=IFCPROPERTYSET('14u6OUyPL5y8O$QkEnB6Rr',$,'EPset_Parametric',$,(#53)); #53=IFCPROPERTYSINGLEVALUE('LayerSetDirection',$,IFCLABEL('AXIS3'),$); -#54=IFCRAMPTYPE('1BTHjVDP19tgb3MDCSkWCJ',$,'RAM200',$,$,$,$,$,$,.NOTDEFINED.); +#54=IFCRAMPTYPE('2G4JrZ99j2B9SkIwWDk0sC',$,'RAM200',$,$,$,$,$,$,.NOTDEFINED.); #55=IFCMATERIALLAYERSET((#57),$,$); -#56=IFCRELASSOCIATESMATERIAL('3HN21bHtL16vvHA2GnnxH1',$,$,$,(#54),#55); +#56=IFCRELASSOCIATESMATERIAL('2nNlFzNPj0_h6_NwdVJvW$',$,$,$,(#54),#55); #57=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$); #58=IFCCIRCLEPROFILEDEF(.AREA.,$,$,0.3); -#59=IFCPILETYPE('04_2WZSqH8TgT7ET6DCCpd',$,'P1',$,$,$,$,$,$,.NOTDEFINED.); +#59=IFCPILETYPE('3uIc5iHjP5Lel3X6KXyN8W',$,'P1',$,$,$,$,$,$,.NOTDEFINED.); #60=IFCMATERIALPROFILESET($,$,(#62),$); -#61=IFCRELASSOCIATESMATERIAL('1qTZZRXsPF9hmYwT$tgFgp',$,$,$,(#59),#60); +#61=IFCRELASSOCIATESMATERIAL('13buLvs1r5vAyhgbabb2g1',$,$,$,(#59),#60); #62=IFCMATERIALPROFILE($,$,#20,#58,$,$); -#63=IFCSLABTYPE('3_OV9$Sd52KRhIW2TWIxbW',$,'FLR150',$,$,$,$,$,$,.NOTDEFINED.); +#63=IFCSLABTYPE('2CbahfxvnFpPoHyMBpGTQm',$,'FLR150',$,$,$,$,$,$,.NOTDEFINED.); #64=IFCMATERIALLAYERSET((#66),$,$); -#65=IFCRELASSOCIATESMATERIAL('1agyf45$X1NhR127pUL0Iw',$,$,$,(#63),#64); +#65=IFCRELASSOCIATESMATERIAL('2Irb7$9xL8YOXW99sF0SOp',$,$,$,(#63),#64); #66=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$); -#67=IFCSLABTYPE('0LvmpIGf9AVPcG$Kt06TEk',$,'FLR250',$,$,$,$,$,$,.NOTDEFINED.); +#67=IFCSLABTYPE('04dx2Vg4vEp9ZOKGI1ifWb',$,'FLR250',$,$,$,$,$,$,.NOTDEFINED.); #68=IFCMATERIALLAYERSET((#70),$,$); -#69=IFCRELASSOCIATESMATERIAL('0EKQPSL656secN86SgeutH',$,$,$,(#67),#68); +#69=IFCRELASSOCIATESMATERIAL('04tl3Me6T6xOb$WEvv_dL0',$,$,$,(#67),#68); #70=IFCMATERIALLAYER(#20,0.3,$,$,$,$,$); #71=IFCRECTANGLEPROFILEDEF(.AREA.,'500x600',$,0.5,0.6); -#72=IFCCOLUMNTYPE('1SI8m9m813tAXfSnM1fCbm',$,'C1',$,$,$,$,$,$,.NOTDEFINED.); +#72=IFCCOLUMNTYPE('13rk_6wmDApeVQWfrArKbl',$,'C1',$,$,$,$,$,$,.NOTDEFINED.); #73=IFCMATERIALPROFILESET($,$,(#75),$); -#74=IFCRELASSOCIATESMATERIAL('1EhwSTRtPBQgBt2x6dhuT$',$,$,$,(#72),#73); +#74=IFCRELASSOCIATESMATERIAL('0X3OUScT9E1BjOvJWiUrv3',$,$,$,(#72),#73); #75=IFCMATERIALPROFILE($,$,#20,#71,$,$); #76=IFCCIRCLEHOLLOWPROFILEDEF(.AREA.,'500.0x5.0 CHS',$,0.25,0.005); -#77=IFCCOLUMNTYPE('25GZwy2zLFcgi57r5S8iY3',$,'C2',$,$,$,$,$,$,.NOTDEFINED.); +#77=IFCCOLUMNTYPE('0IaS5T1Uv6DQu$BJ5I3bks',$,'C2',$,$,$,$,$,$,.NOTDEFINED.); #78=IFCMATERIALPROFILESET($,$,(#80),$); -#79=IFCRELASSOCIATESMATERIAL('2VURAOhz93ZQqT9YJUA1DO',$,$,$,(#77),#78); +#79=IFCRELASSOCIATESMATERIAL('1HWcDe7a17WwPeKCHnckid',$,$,$,(#77),#78); #80=IFCMATERIALPROFILE($,$,#20,#76,$,$); #81=IFCRECTANGLEHOLLOWPROFILEDEF(.AREA.,'150x75x2.0 RHS',$,0.075,0.15,0.002,0.005,0.005); -#82=IFCCOLUMNTYPE('1Wg$I84s9BTh$iDuZnmSkH',$,'C3',$,$,$,$,$,$,.NOTDEFINED.); +#82=IFCCOLUMNTYPE('13p6$J2Jv84RFI5QAp6FTQ',$,'C3',$,$,$,$,$,$,.NOTDEFINED.); #83=IFCMATERIALPROFILESET($,$,(#85),$); -#84=IFCRELASSOCIATESMATERIAL('3fIIwEe7DAle7x_zISvMUD',$,$,$,(#82),#83); +#84=IFCRELASSOCIATESMATERIAL('1GWCzHY657$9kUJrD0AEir',$,$,$,(#82),#83); #85=IFCMATERIALPROFILE($,$,#20,#81,$,$); #86=IFCISHAPEPROFILEDEF(.AREA.,'DEMO-I',$,0.1,0.2,0.005,0.01,0.005,$,$); -#87=IFCBEAMTYPE('2yg2Irs7L26gFsD_AvvFUu',$,'B1',$,$,$,$,$,$,.NOTDEFINED.); +#87=IFCBEAMTYPE('1Y_PtOyJP9YfZkU59r$vs1',$,'B1',$,$,$,$,$,$,.NOTDEFINED.); #88=IFCMATERIALPROFILESET($,$,(#90),$); -#89=IFCRELASSOCIATESMATERIAL('1PU_gbkifF9hYpi9DvXTAU',$,$,$,(#87),#88); +#89=IFCRELASSOCIATESMATERIAL('2CfmfKJ0X45xijxsDUHZ85',$,$,$,(#87),#88); #90=IFCMATERIALPROFILE($,$,#20,#86,$,$); #91=IFCCSHAPEPROFILEDEF(.AREA.,'DEMO-C',$,0.2,0.1,0.0015,0.03,0.005); -#92=IFCBEAMTYPE('2Nf2L5qpz8K8KhUNFBg_fT',$,'B2',$,$,$,$,$,$,.NOTDEFINED.); +#92=IFCBEAMTYPE('2qogXGNrb9EANilnZjnGjq',$,'B2',$,$,$,$,$,$,.NOTDEFINED.); #93=IFCMATERIALPROFILESET($,$,(#95),$); -#94=IFCRELASSOCIATESMATERIAL('1SgarGNCzEQQpfs29NMq0y',$,$,$,(#92),#93); +#94=IFCRELASSOCIATESMATERIAL('3$1pGIrVLA2RTOmJIsbelu',$,$,$,(#92),#93); #95=IFCMATERIALPROFILE($,$,#20,#91,$,$); -#96=IFCWINDOWTYPE('2zRUFP8Ef81xDOR2iJx1zK',$,'WT01',$,$,$,(#135,#152),$,$,.NOTDEFINED.,.NOTDEFINED.,$,$); +#96=IFCWINDOWTYPE('1Dc9pAExL3fxL9jScEo2EF',$,'WT01',$,$,$,(#135,#152),$,$,.NOTDEFINED.,.NOTDEFINED.,$,$); #97=IFCINDEXEDPOLYGONALFACE((13,17,18,14)); #98=IFCINDEXEDPOLYGONALFACE((5,6,3,4)); #99=IFCINDEXEDPOLYGONALFACE((7,8,2,1)); @@ -157,7 +157,7 @@ DATA; #150=IFCDIRECTION((0.,0.,1.)); #151=IFCAXIS2PLACEMENT3D(#148,#150,#149); #152=IFCREPRESENTATIONMAP(#151,#147); -#153=IFCDOORTYPE('0oekOIA$z8lxWiQs9_tFWU',$,'DT01',$,$,$,(#196,#209),$,$,.NOTDEFINED.,.NOTDEFINED.,$,$); +#153=IFCDOORTYPE('05Z1DhJjj11wczPRkvXSPE',$,'DT01',$,$,$,(#196,#209),$,$,.NOTDEFINED.,.NOTDEFINED.,$,$); #154=IFCINDEXEDPOLYGONALFACE((17,16,15,14)); #155=IFCINDEXEDPOLYGONALFACE((2,3,29,28)); #156=IFCINDEXEDPOLYGONALFACE((27,28,29,30,32,31)); @@ -214,7 +214,7 @@ DATA; #207=IFCDIRECTION((0.,0.,1.)); #208=IFCAXIS2PLACEMENT3D(#205,#207,#206); #209=IFCREPRESENTATIONMAP(#208,#204); -#210=IFCFURNITURETYPE('0I2mc$m3T60hLXZYg9Y1wu',$,'BUN01',$,$,$,(#931,#952),$,$,.NOTDEFINED.,.NOTDEFINED.); +#210=IFCFURNITURETYPE('3ZMmSB_rfBnhrBckPTFKvP',$,'BUN01',$,$,$,(#931,#952),$,$,.NOTDEFINED.,.NOTDEFINED.); #211=IFCINDEXEDPOLYGONALFACE((187,278,44)); #212=IFCINDEXEDPOLYGONALFACE((21,52,60)); #213=IFCINDEXEDPOLYGONALFACE((91,100,31)); @@ -957,131 +957,140 @@ DATA; #950=IFCDIRECTION((0.,0.,1.)); #951=IFCAXIS2PLACEMENT3D(#948,#950,#949); #952=IFCREPRESENTATIONMAP(#951,#947); -#953=IFCTYPEPRODUCT('2be705eyD4DPBr6j4K7ZEx',$,'DASHED',$,'IfcAnnotation/LINEWORK',(#954),$,$); -#954=IFCPROPERTYSET('0uEfutIxDDIxMIBUJOZpSM',$,'EPset_Annotation',$,(#955)); -#955=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('dashed'),$); -#956=IFCTYPEPRODUCT('1M7mm9wUHFoxdM0MdAMyqM',$,'FINE',$,'IfcAnnotation/LINEWORK',(#957),$,$); -#957=IFCPROPERTYSET('3AZ8m1Bdn1gfbvagzKr2c3',$,'EPset_Annotation',$,(#958)); -#958=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('fine'),$); -#959=IFCTYPEPRODUCT('3LdrNIFOvAkBzrNnqWAZfA',$,'THIN',$,'IfcAnnotation/LINEWORK',(#960),$,$); -#960=IFCPROPERTYSET('0$9iwgSID7xBul4Tb9r2du',$,'EPset_Annotation',$,(#961)); -#961=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('thin'),$); -#962=IFCTYPEPRODUCT('3fFNO0t1TB$wYRaIkKwUCH',$,'MEDIUM',$,'IfcAnnotation/LINEWORK',(#963),$,$); -#963=IFCPROPERTYSET('33Fm$9zgb1cgsCOy859RlR',$,'EPset_Annotation',$,(#964)); -#964=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('medium'),$); -#965=IFCTYPEPRODUCT('1CpMBhemj5VQC43bU9J7zG',$,'THICK',$,'IfcAnnotation/LINEWORK',(#966),$,$); -#966=IFCPROPERTYSET('1OLDsFSDz2TPz5ifkQvWo8',$,'EPset_Annotation',$,(#967)); -#967=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('thick'),$); -#968=IFCTYPEPRODUCT('0NITtya3b16hoA3sh17SL4',$,'STRONG',$,'IfcAnnotation/LINEWORK',(#969),$,$); -#969=IFCPROPERTYSET('1_kfqWVDn0puI29Ah6eitX',$,'EPset_Annotation',$,(#970)); -#970=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('strong'),$); -#971=IFCTYPEPRODUCT('0rRN9EsvL5AQ3PorxrZSKM',$,'DOOR-TAG',$,'IfcAnnotation/TEXT',(#972),(#991),$); -#972=IFCPROPERTYSET('3lRZ$d2VH8cxZYh$mm45iq',$,'EPset_Annotation',$,(#973)); -#973=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('door-tag'),$); -#974=IFCCARTESIANPOINT((0.,0.,0.)); -#975=IFCDIRECTION((0.,0.,1.)); -#976=IFCDIRECTION((1.,0.,0.)); -#977=IFCAXIS2PLACEMENT3D(#974,#975,#976); -#978=IFCPLANAREXTENT(1000.,1000.); -#979=IFCTEXTLITERALWITHEXTENT('{{type.Name}}',#977,.RIGHT.,#978,'center'); -#980=IFCCARTESIANPOINT((0.,0.,0.)); -#981=IFCDIRECTION((0.,0.,1.)); -#982=IFCDIRECTION((1.,0.,0.)); -#983=IFCAXIS2PLACEMENT3D(#980,#981,#982); -#984=IFCPLANAREXTENT(1000.,1000.); -#985=IFCTEXTLITERALWITHEXTENT('{{Name}}',#983,.RIGHT.,#984,'center'); -#986=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#979,#985)); -#987=IFCCARTESIANPOINT((0.,0.,0.)); -#988=IFCDIRECTION((1.,0.,0.)); -#989=IFCDIRECTION((0.,0.,1.)); -#990=IFCAXIS2PLACEMENT3D(#987,#989,#988); -#991=IFCREPRESENTATIONMAP(#990,#986); -#992=IFCTYPEPRODUCT('0bFZUWHjbA2e03hRHNinTt',$,'WINDOW-TAG',$,'IfcAnnotation/TEXT',(#993),(#1006),$); -#993=IFCPROPERTYSET('3TJOWv5NDBXBNCshYFjsFV',$,'EPset_Annotation',$,(#994)); -#994=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('window-tag'),$); -#995=IFCCARTESIANPOINT((0.,0.,0.)); -#996=IFCDIRECTION((0.,0.,1.)); +#953=IFCTYPEPRODUCT('1hmWolVQb9buX2GhHwaVFB',$,'SETOUT-POINT',$,'IfcAnnotation/SYMBOL',(#954),$,$); +#954=IFCPROPERTYSET('2YNCFr62b8vhuhHGspQl4$',$,'EPset_Annotation',$,(#955)); +#955=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('setout-point'),$); +#956=IFCTYPEPRODUCT('3H4oE1a_9AwQE8OFsCjdfh',$,'CONTROL-POINT',$,'IfcAnnotation/SYMBOL',(#957),$,$); +#957=IFCPROPERTYSET('0ARWSOH$z3kQDRkpEPHWCt',$,'EPset_Annotation',$,(#958)); +#958=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('control-point'),$); +#959=IFCTYPEPRODUCT('3YDPnyrWn2wRWgRzb0V7Kx',$,'TRAVERSE-POINT',$,'IfcAnnotation/SYMBOL',(#960),$,$); +#960=IFCPROPERTYSET('1v$MzHU1b82hDqHdtz4e5y',$,'EPset_Annotation',$,(#961)); +#961=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('traverse-point'),$); +#962=IFCTYPEPRODUCT('31Em8$VNL0Mh$9EZ3pXjpL',$,'DASHED',$,'IfcAnnotation/LINEWORK',(#963),$,$); +#963=IFCPROPERTYSET('0K84$piRb31PmkAwZfP5kd',$,'EPset_Annotation',$,(#964)); +#964=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('dashed'),$); +#965=IFCTYPEPRODUCT('3P0K0gDxP4NgwnuLGqlyW6',$,'FINE',$,'IfcAnnotation/LINEWORK',(#966),$,$); +#966=IFCPROPERTYSET('179vwKcVv9uet4_kI4NT9G',$,'EPset_Annotation',$,(#967)); +#967=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('fine'),$); +#968=IFCTYPEPRODUCT('0Rh30iszn41xBCgQJl2w2c',$,'THIN',$,'IfcAnnotation/LINEWORK',(#969),$,$); +#969=IFCPROPERTYSET('0bZV_Tby121uj5O3n08l1l',$,'EPset_Annotation',$,(#970)); +#970=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('thin'),$); +#971=IFCTYPEPRODUCT('3ti_6xztr7qPp9dASz9vP4',$,'MEDIUM',$,'IfcAnnotation/LINEWORK',(#972),$,$); +#972=IFCPROPERTYSET('19ZhF3bxL07evL8gi27Kei',$,'EPset_Annotation',$,(#973)); +#973=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('medium'),$); +#974=IFCTYPEPRODUCT('2hlcxjzxv8zf0gh1md23xY',$,'THICK',$,'IfcAnnotation/LINEWORK',(#975),$,$); +#975=IFCPROPERTYSET('0wRtpbInzE2AkqX8RIreQr',$,'EPset_Annotation',$,(#976)); +#976=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('thick'),$); +#977=IFCTYPEPRODUCT('1pefU$PA1ENw7kZG9T3mjr',$,'STRONG',$,'IfcAnnotation/LINEWORK',(#978),$,$); +#978=IFCPROPERTYSET('1RpJZBysn8shqevvAquPQ8',$,'EPset_Annotation',$,(#979)); +#979=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('strong'),$); +#980=IFCTYPEPRODUCT('1HKC8zCIv5_ef3dEfa$L5N',$,'DOOR-TAG',$,'IfcAnnotation/TEXT',(#981),(#1000),$); +#981=IFCPROPERTYSET('0aC8JrqFX6HhKUhjdLw4mN',$,'EPset_Annotation',$,(#982)); +#982=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('door-tag'),$); +#983=IFCCARTESIANPOINT((0.,0.,0.)); +#984=IFCDIRECTION((0.,0.,1.)); +#985=IFCDIRECTION((1.,0.,0.)); +#986=IFCAXIS2PLACEMENT3D(#983,#984,#985); +#987=IFCPLANAREXTENT(1000.,1000.); +#988=IFCTEXTLITERALWITHEXTENT('{{type.Name}}',#986,.RIGHT.,#987,'center'); +#989=IFCCARTESIANPOINT((0.,0.,0.)); +#990=IFCDIRECTION((0.,0.,1.)); +#991=IFCDIRECTION((1.,0.,0.)); +#992=IFCAXIS2PLACEMENT3D(#989,#990,#991); +#993=IFCPLANAREXTENT(1000.,1000.); +#994=IFCTEXTLITERALWITHEXTENT('{{Name}}',#992,.RIGHT.,#993,'center'); +#995=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#988,#994)); +#996=IFCCARTESIANPOINT((0.,0.,0.)); #997=IFCDIRECTION((1.,0.,0.)); -#998=IFCAXIS2PLACEMENT3D(#995,#996,#997); -#999=IFCPLANAREXTENT(1000.,1000.); -#1000=IFCTEXTLITERALWITHEXTENT('{{Name}}',#998,.RIGHT.,#999,'center'); -#1001=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1000)); -#1002=IFCCARTESIANPOINT((0.,0.,0.)); -#1003=IFCDIRECTION((1.,0.,0.)); -#1004=IFCDIRECTION((0.,0.,1.)); -#1005=IFCAXIS2PLACEMENT3D(#1002,#1004,#1003); -#1006=IFCREPRESENTATIONMAP(#1005,#1001); -#1007=IFCTYPEPRODUCT('2DlmDdasX05un_uMP4O23U',$,'SPACE-TAG',$,'IfcAnnotation/TEXT',(#1008),(#1033),$); -#1008=IFCPROPERTYSET('1$OAHURHr3GON7ZzAJnv72',$,'EPset_Annotation',$,(#1009)); -#1009=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('space-tag'),$); -#1010=IFCCARTESIANPOINT((0.,0.,0.)); -#1011=IFCDIRECTION((0.,0.,1.)); +#998=IFCDIRECTION((0.,0.,1.)); +#999=IFCAXIS2PLACEMENT3D(#996,#998,#997); +#1000=IFCREPRESENTATIONMAP(#999,#995); +#1001=IFCTYPEPRODUCT('2Jy_wl$FX8h9mgYT1$Y9oc',$,'WINDOW-TAG',$,'IfcAnnotation/TEXT',(#1002),(#1015),$); +#1002=IFCPROPERTYSET('2ncCyO$LPCzv7kqXZK_Omh',$,'EPset_Annotation',$,(#1003)); +#1003=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('window-tag'),$); +#1004=IFCCARTESIANPOINT((0.,0.,0.)); +#1005=IFCDIRECTION((0.,0.,1.)); +#1006=IFCDIRECTION((1.,0.,0.)); +#1007=IFCAXIS2PLACEMENT3D(#1004,#1005,#1006); +#1008=IFCPLANAREXTENT(1000.,1000.); +#1009=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1007,.RIGHT.,#1008,'center'); +#1010=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1009)); +#1011=IFCCARTESIANPOINT((0.,0.,0.)); #1012=IFCDIRECTION((1.,0.,0.)); -#1013=IFCAXIS2PLACEMENT3D(#1010,#1011,#1012); -#1014=IFCPLANAREXTENT(1000.,1000.); -#1015=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1013,.RIGHT.,#1014,'center'); -#1016=IFCCARTESIANPOINT((0.,0.,0.)); -#1017=IFCDIRECTION((0.,0.,1.)); -#1018=IFCDIRECTION((1.,0.,0.)); -#1019=IFCAXIS2PLACEMENT3D(#1016,#1017,#1018); -#1020=IFCPLANAREXTENT(1000.,1000.); -#1021=IFCTEXTLITERALWITHEXTENT('{{Description}}',#1019,.RIGHT.,#1020,'center'); -#1022=IFCCARTESIANPOINT((0.,0.,0.)); -#1023=IFCDIRECTION((0.,0.,1.)); -#1024=IFCDIRECTION((1.,0.,0.)); -#1025=IFCAXIS2PLACEMENT3D(#1022,#1023,#1024); -#1026=IFCPLANAREXTENT(1000.,1000.); -#1027=IFCTEXTLITERALWITHEXTENT('``round({{Qto_SpaceBaseQuantities.NetFloorArea}} or 0., 2)``',#1025,.RIGHT.,#1026,'center'); -#1028=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1015,#1021,#1027)); -#1029=IFCCARTESIANPOINT((0.,0.,0.)); -#1030=IFCDIRECTION((1.,0.,0.)); -#1031=IFCDIRECTION((0.,0.,1.)); -#1032=IFCAXIS2PLACEMENT3D(#1029,#1031,#1030); -#1033=IFCREPRESENTATIONMAP(#1032,#1028); -#1034=IFCTYPEPRODUCT('2vNx3CIlrFs8bLFlmGvJF3',$,'MATERIAL-TAG',$,'IfcAnnotation/TEXT',(#1035),(#1048),$); -#1035=IFCPROPERTYSET('1l$T4lUqnBb93zcgfbSPvx',$,'EPset_Annotation',$,(#1036)); -#1036=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('rectangle-tag'),$); -#1037=IFCCARTESIANPOINT((0.,0.,0.)); -#1038=IFCDIRECTION((0.,0.,1.)); +#1013=IFCDIRECTION((0.,0.,1.)); +#1014=IFCAXIS2PLACEMENT3D(#1011,#1013,#1012); +#1015=IFCREPRESENTATIONMAP(#1014,#1010); +#1016=IFCTYPEPRODUCT('1LTLrGzxH4qhuWGNeTlTRi',$,'SPACE-TAG',$,'IfcAnnotation/TEXT',(#1017),(#1042),$); +#1017=IFCPROPERTYSET('2JpTIsSZf3zQUWK48RLIcL',$,'EPset_Annotation',$,(#1018)); +#1018=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('space-tag'),$); +#1019=IFCCARTESIANPOINT((0.,0.,0.)); +#1020=IFCDIRECTION((0.,0.,1.)); +#1021=IFCDIRECTION((1.,0.,0.)); +#1022=IFCAXIS2PLACEMENT3D(#1019,#1020,#1021); +#1023=IFCPLANAREXTENT(1000.,1000.); +#1024=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1022,.RIGHT.,#1023,'center'); +#1025=IFCCARTESIANPOINT((0.,0.,0.)); +#1026=IFCDIRECTION((0.,0.,1.)); +#1027=IFCDIRECTION((1.,0.,0.)); +#1028=IFCAXIS2PLACEMENT3D(#1025,#1026,#1027); +#1029=IFCPLANAREXTENT(1000.,1000.); +#1030=IFCTEXTLITERALWITHEXTENT('{{Description}}',#1028,.RIGHT.,#1029,'center'); +#1031=IFCCARTESIANPOINT((0.,0.,0.)); +#1032=IFCDIRECTION((0.,0.,1.)); +#1033=IFCDIRECTION((1.,0.,0.)); +#1034=IFCAXIS2PLACEMENT3D(#1031,#1032,#1033); +#1035=IFCPLANAREXTENT(1000.,1000.); +#1036=IFCTEXTLITERALWITHEXTENT('``round({{Qto_SpaceBaseQuantities.NetFloorArea}} or 0., 2)``',#1034,.RIGHT.,#1035,'center'); +#1037=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1024,#1030,#1036)); +#1038=IFCCARTESIANPOINT((0.,0.,0.)); #1039=IFCDIRECTION((1.,0.,0.)); -#1040=IFCAXIS2PLACEMENT3D(#1037,#1038,#1039); -#1041=IFCPLANAREXTENT(1000.,1000.); -#1042=IFCTEXTLITERALWITHEXTENT('{{material.Name}}',#1040,.RIGHT.,#1041,'center'); -#1043=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1042)); -#1044=IFCCARTESIANPOINT((0.,0.,0.)); -#1045=IFCDIRECTION((1.,0.,0.)); -#1046=IFCDIRECTION((0.,0.,1.)); -#1047=IFCAXIS2PLACEMENT3D(#1044,#1046,#1045); -#1048=IFCREPRESENTATIONMAP(#1047,#1043); -#1049=IFCTYPEPRODUCT('3hqzFtbSb56RjhAZNaB4Vh',$,'TYPE-TAG',$,'IfcAnnotation/TEXT',(#1050),(#1063),$); -#1050=IFCPROPERTYSET('3U7kaKt_nBUvD$U2ryif_H',$,'EPset_Annotation',$,(#1051)); -#1051=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('capsule-tag'),$); -#1052=IFCCARTESIANPOINT((0.,0.,0.)); -#1053=IFCDIRECTION((0.,0.,1.)); +#1040=IFCDIRECTION((0.,0.,1.)); +#1041=IFCAXIS2PLACEMENT3D(#1038,#1040,#1039); +#1042=IFCREPRESENTATIONMAP(#1041,#1037); +#1043=IFCTYPEPRODUCT('3Or$DhaVf6ygGBUpRb2PMs',$,'MATERIAL-TAG',$,'IfcAnnotation/TEXT',(#1044),(#1057),$); +#1044=IFCPROPERTYSET('2YfvIc6dPDdwWjERHZZlof',$,'EPset_Annotation',$,(#1045)); +#1045=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('rectangle-tag'),$); +#1046=IFCCARTESIANPOINT((0.,0.,0.)); +#1047=IFCDIRECTION((0.,0.,1.)); +#1048=IFCDIRECTION((1.,0.,0.)); +#1049=IFCAXIS2PLACEMENT3D(#1046,#1047,#1048); +#1050=IFCPLANAREXTENT(1000.,1000.); +#1051=IFCTEXTLITERALWITHEXTENT('{{material.Name}}',#1049,.RIGHT.,#1050,'center'); +#1052=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1051)); +#1053=IFCCARTESIANPOINT((0.,0.,0.)); #1054=IFCDIRECTION((1.,0.,0.)); -#1055=IFCAXIS2PLACEMENT3D(#1052,#1053,#1054); -#1056=IFCPLANAREXTENT(1000.,1000.); -#1057=IFCTEXTLITERALWITHEXTENT('{{type.Name}}',#1055,.RIGHT.,#1056,'center'); -#1058=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1057)); -#1059=IFCCARTESIANPOINT((0.,0.,0.)); -#1060=IFCDIRECTION((1.,0.,0.)); -#1061=IFCDIRECTION((0.,0.,1.)); -#1062=IFCAXIS2PLACEMENT3D(#1059,#1061,#1060); -#1063=IFCREPRESENTATIONMAP(#1062,#1058); -#1064=IFCTYPEPRODUCT('2SnSxJPiD9sh$NDx92OCSS',$,'NAME-TAG',$,'IfcAnnotation/TEXT',(#1065),(#1078),$); -#1065=IFCPROPERTYSET('3Lu86QVuv5nfjkuPLvdQSH',$,'EPset_Annotation',$,(#1066)); -#1066=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('capsule-tag'),$); -#1067=IFCCARTESIANPOINT((0.,0.,0.)); -#1068=IFCDIRECTION((0.,0.,1.)); +#1055=IFCDIRECTION((0.,0.,1.)); +#1056=IFCAXIS2PLACEMENT3D(#1053,#1055,#1054); +#1057=IFCREPRESENTATIONMAP(#1056,#1052); +#1058=IFCTYPEPRODUCT('01Hhk_DbjDROhyr91Hp$aV',$,'TYPE-TAG',$,'IfcAnnotation/TEXT',(#1059),(#1072),$); +#1059=IFCPROPERTYSET('0LyRD7lHr17uJo7XNzCvZq',$,'EPset_Annotation',$,(#1060)); +#1060=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('capsule-tag'),$); +#1061=IFCCARTESIANPOINT((0.,0.,0.)); +#1062=IFCDIRECTION((0.,0.,1.)); +#1063=IFCDIRECTION((1.,0.,0.)); +#1064=IFCAXIS2PLACEMENT3D(#1061,#1062,#1063); +#1065=IFCPLANAREXTENT(1000.,1000.); +#1066=IFCTEXTLITERALWITHEXTENT('{{type.Name}}',#1064,.RIGHT.,#1065,'center'); +#1067=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1066)); +#1068=IFCCARTESIANPOINT((0.,0.,0.)); #1069=IFCDIRECTION((1.,0.,0.)); -#1070=IFCAXIS2PLACEMENT3D(#1067,#1068,#1069); -#1071=IFCPLANAREXTENT(1000.,1000.); -#1072=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1070,.RIGHT.,#1071,'center'); -#1073=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1072)); -#1074=IFCCARTESIANPOINT((0.,0.,0.)); -#1075=IFCDIRECTION((1.,0.,0.)); -#1076=IFCDIRECTION((0.,0.,1.)); -#1077=IFCAXIS2PLACEMENT3D(#1074,#1076,#1075); -#1078=IFCREPRESENTATIONMAP(#1077,#1073); +#1070=IFCDIRECTION((0.,0.,1.)); +#1071=IFCAXIS2PLACEMENT3D(#1068,#1070,#1069); +#1072=IFCREPRESENTATIONMAP(#1071,#1067); +#1073=IFCTYPEPRODUCT('0a8MHfTUzA5AV8H6p1bqC9',$,'NAME-TAG',$,'IfcAnnotation/TEXT',(#1074),(#1087),$); +#1074=IFCPROPERTYSET('2EboL9u1j68Q_Mp8dBa7ux',$,'EPset_Annotation',$,(#1075)); +#1075=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('capsule-tag'),$); +#1076=IFCCARTESIANPOINT((0.,0.,0.)); +#1077=IFCDIRECTION((0.,0.,1.)); +#1078=IFCDIRECTION((1.,0.,0.)); +#1079=IFCAXIS2PLACEMENT3D(#1076,#1077,#1078); +#1080=IFCPLANAREXTENT(1000.,1000.); +#1081=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1079,.RIGHT.,#1080,'center'); +#1082=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1081)); +#1083=IFCCARTESIANPOINT((0.,0.,0.)); +#1084=IFCDIRECTION((1.,0.,0.)); +#1085=IFCDIRECTION((0.,0.,1.)); +#1086=IFCAXIS2PLACEMENT3D(#1083,#1085,#1084); +#1087=IFCREPRESENTATIONMAP(#1086,#1082); ENDSEC; END-ISO-10303-21; diff --git a/src/blenderbim/blenderbim/bim/module/drawing/annotation.py b/src/blenderbim/blenderbim/bim/module/drawing/annotation.py index 9188291f40..a4473764cc 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/annotation.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/annotation.py @@ -92,6 +92,15 @@ class Annotator: return obj + @staticmethod + def add_vertex_to_annotation(obj): + verts_world_space = Annotator.get_placeholder_coords() + vert_local = obj.matrix_world.inverted() @ verts_world_space[0] + bm = tool.Blender.get_bmesh_for_mesh(obj.data, clean=True) + bm.verts.new(vert_local) + tool.Blender.apply_bmesh(obj.data, bm, obj) + return obj + @staticmethod def add_plane_to_annotation(obj, remove_face=False): # default order = bot left, top left, bot right, top right @@ -144,6 +153,8 @@ class Annotator: data = bpy.data.curves.new(object_type, type="CURVE") data.dimensions = "3D" data.resolution_u = 2 + elif data_type == "empty": + data = None obj = bpy.data.objects.new(object_type, data) obj.matrix_world = matrix_world diff --git a/src/blenderbim/blenderbim/bim/module/drawing/prop.py b/src/blenderbim/blenderbim/bim/module/drawing/prop.py index cab0f75ddc..0578ff8105 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/prop.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/prop.py @@ -502,6 +502,8 @@ ANNOTATION_TYPES_DATA = { "PLAN_LEVEL": ("Level (Plan)", "", "SORTBYEXT", "curve"), "SECTION_LEVEL": ("Level (Section)", "", "TRIA_DOWN", "curve"), "BREAKLINE": ("Breakline", "", "FCURVE", "mesh"), + "SYMBOL": ("Symbol", "", "KEYFRAME", "empty"), + "MULTI_SYMBOL": ("Multi-Symbol", "", "OUTLINER_DATA_POINTCLOUD", "mesh"), "LINEWORK": ("Line", "", "SNAP_MIDPOINT", "mesh"), "BATTING": ("Batting", "Add batting annotation.\nThickness could be changed through Thickness property of BBIM_Batting property set", "FORCE_FORCE", "mesh"), "REVISION_CLOUD":("Revision Cloud", "Add revision cloud", "VOLUME_DATA", "mesh"), diff --git a/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py index a987157c63..23cbf1ab0f 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py @@ -326,11 +326,12 @@ class SvgWriter: # We have to decide whether this should come from Blender or from IFC. # For the moment, for convenience of experimenting with ideas, it comes # from Blender. In the future, it should probably come from IFC. - if not isinstance(obj.data, bpy.types.Mesh): - return - classes = self.get_attribute_classes(obj) - if len(obj.data.vertices) and not len(obj.data.edges): + if obj.data is None: + return self.draw_empty_annotation(obj, classes) + elif not isinstance(obj.data, bpy.types.Mesh): + return + elif len(obj.data.vertices) and not len(obj.data.edges): return self.draw_point_annotation(obj, classes) elif len(obj.data.polygons) == 0: return self.draw_edge_annotation(obj, classes) @@ -862,6 +863,27 @@ class SvgWriter: self.svg.add(tag) line_number += len(tag.elements) + def draw_empty_annotation(self, obj, classes): + x_offset = self.raw_width / 2 + y_offset = self.raw_height / 2 + + point = self.project_point_onto_camera(obj.matrix_world.translation) + + element = tool.Ifc.get_entity(obj) + svg_id = ifcopenshell.util.element.get_pset(element, "EPset_Annotation", "Symbol") + if not svg_id: + # EPset_AnnotationSurveyArea is not standard! See bSI-4.3 proposal #660. + svg_id = ifcopenshell.util.element.get_pset(element, "EPset_AnnotationSurveyArea", "PointType") + if not svg_id: + svg_id = str(ifcopenshell.util.element.get_predefined_type(element)) + if not svg_id: + return + + point = Vector(((x_offset + point.x), (y_offset - point.y))) + symbol_position_svg = point * self.svg_scale + self.svg.add(self.svg.use(f"#{svg_id}", insert=symbol_position_svg)) + + def draw_point_annotation(self, obj, classes): x_offset = self.raw_width / 2 y_offset = self.raw_height / 2 @@ -870,12 +892,14 @@ class SvgWriter: projected_points = [self.project_point_onto_camera(matrix_world @ v.co) for v in obj.data.vertices] element = tool.Ifc.get_entity(obj) - svg_id = str(ifcopenshell.util.element.get_predefined_type(element)) - - # EPset_AnnotationSurveyArea is not standard! See bSI-4.3 proposal #660. - point_type = ifcopenshell.util.element.get_pset(element, "EPset_AnnotationSurveyArea", "PointType") - if point_type: - svg_id += f"-{point_type}" + svg_id = ifcopenshell.util.element.get_pset(element, "EPset_Annotation", "Symbol") + if not svg_id: + # EPset_AnnotationSurveyArea is not standard! See bSI-4.3 proposal #660. + svg_id = ifcopenshell.util.element.get_pset(element, "EPset_AnnotationSurveyArea", "PointType") + if not svg_id: + svg_id = str(ifcopenshell.util.element.get_predefined_type(element)) + if not svg_id: + return for symbol_position in projected_points: symbol_position = Vector(((x_offset + symbol_position.x), (y_offset - symbol_position.y))) diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index 36b99fb044..8c2751c4f6 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -71,6 +71,8 @@ class Drawing(blenderbim.core.tool.Drawing): obj = annotation.Annotator.add_plane_to_annotation(obj) elif object_type == "REVISION_CLOUD": obj = annotation.Annotator.add_plane_to_annotation(obj, remove_face=True) + elif object_type == "MULTI_SYMBOL": + obj = annotation.Annotator.add_vertex_to_annotation(obj) elif object_type == "TEXT_LEADER": co1, _, co2, _ = annotation.Annotator.get_placeholder_coords() obj = annotation.Annotator.add_line_to_annotation(obj, co2, co1) diff --git a/src/blenderbim/scripts/generate_demo_library.py b/src/blenderbim/scripts/generate_demo_library.py index e0017925db..7f5775a39f 100644 --- a/src/blenderbim/scripts/generate_demo_library.py +++ b/src/blenderbim/scripts/generate_demo_library.py @@ -146,6 +146,9 @@ class LibraryGenerator: self.create_type("IfcDoorType", "DT01", {"model_body": "Door", "plan_body": "Door-Plan"}) self.create_type("IfcFurnitureType", "BUN01", {"model_body": "Bunny", "plan_body": "Bunny-Plan"}) + self.create_symbol_type("SETOUT-POINT", "setout-point") + self.create_symbol_type("CONTROL-POINT", "control-point") + self.create_symbol_type("TRAVERSE-POINT", "traverse-point") self.create_line_type("DASHED", "dashed") self.create_line_type("FINE", "fine") self.create_line_type("THIN", "thin") @@ -161,6 +164,12 @@ class LibraryGenerator: self.file.write("IFC4 Demo Library.ifc") + def create_symbol_type(self, name, symbol): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcTypeProduct", name=name) + element.ApplicableOccurrence = "IfcAnnotation/SYMBOL" + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Annotation") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Symbol": symbol}) + def create_line_type(self, name, classes): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcTypeProduct", name=name) element.ApplicableOccurrence = "IfcAnnotation/LINEWORK" diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py index 8b458ef777..31bf7f1f98 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py @@ -823,6 +823,8 @@ class Usecase: def create_annotation2d_representation(self): if isinstance(self.settings["geometry"], bpy.types.Mesh) and len(self.settings["geometry"].polygons): items = self.create_annotation_fill_areas(is_2d=True) + elif isinstance(self.settings["geometry"], bpy.types.Mesh) and not len(self.settings["geometry"].edges): + return self.create_point_cloud_representation(is_2d=True) else: items = [self.file.createIfcGeometricCurveSet(self.create_curves(is_2d=True))] return self.file.createIfcShapeRepresentation( From 46cfe7018157f1de7df4aa0d98eba11dccf96490 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 2 Sep 2023 16:29:46 +1000 Subject: [PATCH 80/81] You can now load 2D point clouds. --- src/blenderbim/blenderbim/bim/import_ifc.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index 266cec2784..5c20aea10c 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -980,10 +980,14 @@ class IfcImporter: placement_matrix = self.get_element_matrix(product) vertex_list = [] for item in representation.Items: - if item.is_a("IfcCartesianPointList"): + if item.is_a("IfcCartesianPointList3D"): vertex_list.extend( mathutils.Vector(list(coordinates)) * self.unit_scale for coordinates in item.CoordList ) + elif item.is_a("IfcCartesianPointList2D"): + vertex_list.extend( + mathutils.Vector(list(coordinates)).to_3d() * self.unit_scale for coordinates in item.CoordList + ) elif item.is_a("IfcCartesianPoint"): vertex_list.append(mathutils.Vector(list(item.Coordinates)) * self.unit_scale) From eee844e2045e97d72f2266f620d6c7e43d7a353f Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 2 Sep 2023 15:58:05 +0200 Subject: [PATCH 81/81] Express rules: Workaround str case in IfcBlobTexture --- .../ifcopenshell/express/rule_compiler.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ifcopenshell-python/ifcopenshell/express/rule_compiler.py b/src/ifcopenshell-python/ifcopenshell/express/rule_compiler.py index e844c8d605..b617036f8a 100644 --- a/src/ifcopenshell-python/ifcopenshell/express/rule_compiler.py +++ b/src/ifcopenshell-python/ifcopenshell/express/rule_compiler.py @@ -420,6 +420,15 @@ def process_expression(context): exclude=[context.rel_op_extended], ) else: + if len(context.simple_expression.branches()) == 2 and str(context.rel_op_extended) == 'in': + # IfcBlobTexture + try: + is_literal_str_list = set(map(type, ast.literal_eval(str(context.simple_expression.branches()[1])))) == {str} + except: + is_literal_str_list = False + if is_literal_str_list: + a, b = map(str, context.simple_expression.branches()) + return f"{a}.lower() {str(context.rel_op_extended)} {b}" return concat(context.rel_op_extended, context.simple_expression) elif context.multiplication_like_op: if str(context.multiplication_like_op.branches()[0]) == "||":