diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index 328804d4c6..f5a1e534da 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -466,13 +466,14 @@ class PolylineDecorator: self.addon_prefs = tool.Blender.get_addon_preferences() self.font_id = 0 - font_size = tool.Blender.scale_font_size(12) + font_size = tool.Blender.scale_font_size() + offset = tool.Blender.scale_font_size() * 1.5 + line_height = tool.Blender.scale_font_size() * 1.25 blf.size(self.font_id, font_size) blf.enable(self.font_id, blf.SHADOW) blf.shadow(self.font_id, 6, 0, 0, 0, 1) color = self.addon_prefs.decorations_colour color_highlight = self.addon_prefs.decorator_color_special - offset = 20 new_line = 0 for i, (key, field_name) in enumerate(texts.items()): formatted_value = None @@ -480,7 +481,7 @@ class PolylineDecorator: # Controls which options are displayed in the UI if key not in self.input_ui.input_options: continue - new_line += 20 + new_line += line_height if self.tool_state and key != self.tool_state.input_type: formatted_value = self.input_ui.get_formatted_value(key) else: @@ -515,7 +516,7 @@ class PolylineDecorator: self.addon_prefs = tool.Blender.get_addon_preferences() self.font_id = 1 self.shader = gpu.shader.from_builtin("UNIFORM_COLOR") - font_size = tool.Blender.scale_font_size(12) + font_size = tool.Blender.scale_font_size() blf.size(self.font_id, font_size) blf.enable(self.font_id, blf.SHADOW) blf.shadow(self.font_id, 6, 0, 0, 0, 1) @@ -1936,7 +1937,7 @@ class BoundingBoxDecorator: addon_prefs = tool.Blender.get_addon_preferences() font_id = 0 - font_size = tool.Blender.scale_font_size(12) + font_size = tool.Blender.scale_font_size() blf.size(font_id, font_size) blf.enable(font_id, blf.SHADOW) blf.shadow(font_id, 6, 0, 0, 0, 1) diff --git a/src/bonsai/bonsai/bim/ui.py b/src/bonsai/bonsai/bim/ui.py index 30ce93f076..26c06c5b8d 100644 --- a/src/bonsai/bonsai/bim/ui.py +++ b/src/bonsai/bonsai/bim/ui.py @@ -747,6 +747,12 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): default=".ifc.metadata.blend", ) + decorator_font_scale: bpy.props.FloatProperty( + name="Decorator Font Scale", + description="Scale factor for decorator font size.", + default=1.0, + ) + if TYPE_CHECKING: svg2pdf_command: str svg2dxf_command: str @@ -786,6 +792,7 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): mass_time_units_in_wizard: bool chain_filter_with_set_operations: bool save_metadata_blend_file: bool + decorator_font_scale: float def draw(self, context: bpy.types.Context) -> None: layout = self.layout @@ -1009,6 +1016,7 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): else: row = layout.row() row.operator("bim.manage_tab_visibility", icon="PREFERENCES") + layout.prop(self, "decorator_font_scale") # Scene panel groups diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index a2a0f09ed8..9471cad28c 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -1571,13 +1571,18 @@ class Blender(bonsai.core.tool.Blender): return getattr(scene, "sun_pos_properties", None) @classmethod - def scale_font_size(cls, size): + def scale_font_size(cls, size=None): default_dpi = 72 default_pixel_size = 1.0 + ui_style = bpy.context.preferences.ui_styles[0] + base_size = ui_style.widget.points if size is None else size + platform_scale = 0.5 if sys.platform == "darwin" else 1 + default_scale = default_dpi * default_pixel_size system = bpy.context.preferences.system system_scale = system.dpi * system.pixel_size - return (system_scale / default_scale) * size + return (system_scale / default_scale) * base_size *platform_scale * tool.Blender.get_addon_preferences().decorator_font_scale + @classmethod def apply_transform_as_local(cls, obj: bpy.types.Object) -> bool: diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py index 148f4a6b75..0f3f4e45ad 100644 --- a/src/bonsai/bonsai/tool/model.py +++ b/src/bonsai/bonsai/tool/model.py @@ -1244,18 +1244,7 @@ class Model(bonsai.core.tool.Model): height = 100 - is_horizontal = False - if element.is_a("IfcSlabType"): - is_horizontal = True - - parametric = ifcopenshell.util.element.get_psets(element).get("EPset_Parametric") - if parametric: - layer_set_direction = parametric.get("LayerSetDirection", None) - if layer_set_direction == "AXIS2": - is_horizontal = False - elif layer_set_direction == "AXIS3": - is_horizontal = True - + is_horizontal = cls.get_usage_type(element) == "LAYER3" if is_horizontal: width, height = height, width @@ -1266,7 +1255,7 @@ class Model(bonsai.core.tool.Model): del thicknesses[-1] for thickness in thicknesses: current_thickness += thickness - if element.is_a("IfcSlabType"): + if is_horizontal: y = (current_thickness / total_thickness) * height line = [x_offset, y_offset + y, x_offset + width, y_offset + y] else: diff --git a/src/ifcgeom/kernels/opencascade/loft.cpp b/src/ifcgeom/kernels/opencascade/loft.cpp index 74c9c187df..b055b7743b 100644 --- a/src/ifcgeom/kernels/opencascade/loft.cpp +++ b/src/ifcgeom/kernels/opencascade/loft.cpp @@ -165,13 +165,6 @@ bool OpenCascadeKernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape& re std::vector shps(loft->children.size()); std::vector>> all_tags; - - std::ostringstream oss; - loft->children[0]->print(oss); - loft->children[1]->print(oss); - auto s = oss.str(); - std::wcout << s.c_str() << std::endl; - // First convert all taxonomy items to TopoDS_Wire/Face for (auto it = loft->children.begin(); it < loft->children.end(); ++it) { auto i = std::distance(loft->children.begin(), it); @@ -267,6 +260,18 @@ bool OpenCascadeKernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape& re return true; */ + if (shps.size() < 2) { + Logger::Error("Not enough sections to loft"); + return false; + } + + if (shps[0].ShapeType() == TopAbs_FACE) { + // When processing a sectioned *surface* there are no + // begin and end caps that need to be added. + BB.Add(comp, shps.front().Reversed()); + BB.Add(comp, shps.back()); + } + // @todo this approach is // potentially incorrect as there is no guarantee that the wires for // subsequently placed profiles are traversed from an equivalent start vertex. @@ -292,18 +297,6 @@ bool OpenCascadeKernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape& re ws[0][i] = TopoDS::Wire(*fa[i]); } } - if (it->ShapeType() == TopAbs_FACE) { - // When processing a sectioned *surface* there are no - // begin and end caps that need to be added. - if (it == shps.begin()) { - // faces.Append(shps[0]); - BB.Add(comp, shps[0]); - } - if (jt == shps.end() - 1) { - // faces.Append(shps[1]); - BB.Add(comp, shps[1]); - } - } if (!all_tags.empty()) { // only open profiles have tags for now, so there is only one wire, no inner wires diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst b/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst index 2d0cc9e071..4e28e83ed4 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst @@ -254,7 +254,7 @@ nest formulas, for example ``concat(title("foo"), lower("Bar"))`` will produce "``imperial_length({{value}}, {{precision}}, {{input_unit}}, {{output_unit}}, {{suppress_zero_inches}})``", "``imperial_length(3.0, 4, ""foot"", ""foot"", true)`` OR ``imperial_length(3.0, 4, ""foot"", ""foot"", false)``", "``3'`` OR ``3' - 0""``", "The ``{{value}}`` may be specified either as ``foot`` or ``inch`` depending on ``{{input_unit}}``. The ``{{value}}`` is then rounded to the nearest ``1/{{precision}}`` inch, then formatted using fractional feet and inches if ``{{output_unit}}`` is set to ``foot``, or just inches if ``{{output_unit}}`` is set to ``inch``. When ``{{suppress_zero_inches}}`` is ``true`` (default), measurements with zero inches will omit the inch portion (e.g., ``3'`` instead of ``3' - 0""``)." "``sort({{values}})``", "``sort({{mats.Name}})``", "``Name1, Name2``", "Sorts a list of items." "``reverse({{values}})``", "``reverse({{mats.Name}})``", "``Name2, Name1``", "Reverses a list of items." - "``join({{separator}}, {{values}})``", "``join("-", {{mats.Name}})``", "``Name1-Name2``", "Joins a list of items with a custom separator. By default, all lists a rendered as comma separated." + "``join({{separator}}, {{values}})``", "``join(""-"", {{mats.Name}})``", "``Name1-Name2``", "Joins a list of items with a custom separator. By default, all lists a rendered as comma separated." "``{{value1}}[+-*/]{{value2}}``", "``{{z}}+3``", "``5``", "Does arithmetic. Typical operators such as +, -, \*, and / are allowed and can be mixed with other variables and formatting functions." When using queries in an IfcAnnotation tag surround with backticks. diff --git a/src/ifcopenshell-python/ifcopenshell/api/spatial/reference_structure.py b/src/ifcopenshell-python/ifcopenshell/api/spatial/reference_structure.py index 4446971f0d..f19be2360b 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/spatial/reference_structure.py +++ b/src/ifcopenshell-python/ifcopenshell/api/spatial/reference_structure.py @@ -63,14 +63,15 @@ def reference_structure( storey1 = ifcopenshell.api.root.create_entity(model, ifc_class="IfcBuildingStorey") storey2 = ifcopenshell.api.root.create_entity(model, ifc_class="IfcBuildingStorey") storey3 = ifcopenshell.api.root.create_entity(model, ifc_class="IfcBuildingStorey") + space = ifcopenshell.api.root.create_entity(model, ifc_class="IfcSpace") # The project contains a site (note that project aggregation is a special case in IFC) ifcopenshell.api.aggregate.assign_object(model, products=[site], relating_object=project) # The site has a building, the building has a storey, and the storey has a space ifcopenshell.api.aggregate.assign_object(model, products=[building], relating_object=site) - ifcopenshell.api.aggregate.assign_object(model, products=[storey], relating_object=building) - ifcopenshell.api.aggregate.assign_object(model, products=[space], relating_object=storey) + ifcopenshell.api.aggregate.assign_object(model, products=[storey1,storey2,storey3], relating_object=building) + ifcopenshell.api.aggregate.assign_object(model, products=[space], relating_object=storey1) # Create a column, this column spans 3 storeys column = ifcopenshell.api.root.create_entity(model, ifc_class="IfcWall") @@ -80,7 +81,11 @@ def reference_structure( # And referenced in the others ifcopenshell.api.spatial.reference_structure( - model, products=[column], relating_structure=[storey2, storey3] + model, products=[column], relating_structure=storey2 + ) + + ifcopenshell.api.spatial.reference_structure( + model, products=[column], relating_structure=storey3 ) """