mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 02:47:48 +00:00
fix covering test and fix bug adding coverings in non-meters projects
Noticed that adding a covering in millimeters project didn't worked - the reason was that shapely was using tolerance in ifc project units when get_obj_base_points was returning points in si (blender always operates in meters internally). I've changed get_obj_base_points to return data in project units and get_bmesh_from_polygon to convert it back to meters for Blender. It's probably would be better to always operate in si until we need to save data to ifc but I'm not that familiar with that module to just change it everywhere. Ping @maxfb87 just in case.
This commit is contained in:
@@ -490,13 +490,15 @@ class Spatial(blenderbim.core.tool.Spatial):
|
||||
selected_objects = bpy.context.selected_objects
|
||||
boundary_elements = cls.get_boundary_elements(selected_objects)
|
||||
polys = cls.get_polygons(boundary_elements)
|
||||
converted_tolerance = cls.get_converted_tolerance(tolerance=0.03)
|
||||
converted_tolerance = cls.get_converted_tolerance(tolerance_si=0.03)
|
||||
union = shapely.ops.unary_union(polys).buffer(
|
||||
converted_tolerance,
|
||||
cap_style=shapely.constructive.BufferCapStyle.flat,
|
||||
join_style=shapely.constructive.BufferJoinStyle.mitre,
|
||||
)
|
||||
union = cls.get_purged_inner_holes_poly(union_geom=union, min_area=cls.get_converted_tolerance(tolerance=0.1))
|
||||
union = cls.get_purged_inner_holes_poly(
|
||||
union_geom=union, min_area=cls.get_converted_tolerance(tolerance_si=0.1)
|
||||
)
|
||||
return union
|
||||
|
||||
@classmethod
|
||||
@@ -526,28 +528,20 @@ class Spatial(blenderbim.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def get_obj_base_points(cls, obj: bpy.types.Object) -> dict[str, tuple[float, float]]:
|
||||
x_values = [(obj.matrix_world @ Vector(v)).x for v in obj.bound_box]
|
||||
y_values = [(obj.matrix_world @ Vector(v)).y for v in obj.bound_box]
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
bbox_ws = [obj.matrix_world @ Vector(v) / si_conversion for v in obj.bound_box]
|
||||
return {
|
||||
"low_left": (x_values[0], y_values[0]),
|
||||
"high_left": (x_values[3], y_values[3]),
|
||||
"low_right": (x_values[4], y_values[4]),
|
||||
"high_right": (x_values[7], y_values[7]),
|
||||
"low_left": (bbox_ws[0].x, bbox_ws[0].y),
|
||||
"high_left": (bbox_ws[3].x, bbox_ws[3].y),
|
||||
"low_right": (bbox_ws[4].x, bbox_ws[4].y),
|
||||
"high_right": (bbox_ws[7].x, bbox_ws[7].y),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_converted_tolerance(cls, tolerance: float) -> float:
|
||||
def get_converted_tolerance(cls, tolerance_si: float) -> float:
|
||||
model = tool.Ifc.get()
|
||||
project_unit = ifcopenshell.util.unit.get_project_unit(model, "LENGTHUNIT")
|
||||
prefix = getattr(project_unit, "Prefix", None)
|
||||
|
||||
return ifcopenshell.util.unit.convert(
|
||||
value=tolerance,
|
||||
from_prefix=None,
|
||||
from_unit="METRE",
|
||||
to_prefix=prefix,
|
||||
to_unit=project_unit.Name,
|
||||
)
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(model)
|
||||
return tolerance_si / si_conversion
|
||||
|
||||
@classmethod
|
||||
def get_purged_inner_holes_poly(cls, union_geom: Polygon, min_area: float) -> Polygon:
|
||||
@@ -580,7 +574,7 @@ class Spatial(blenderbim.core.tool.Spatial):
|
||||
@classmethod
|
||||
def get_buffered_poly_from_linear_ring(cls, linear_ring: shapely.LinearRing) -> Polygon:
|
||||
poly = Polygon(linear_ring)
|
||||
converted_tolerance = cls.get_converted_tolerance(tolerance=0.03)
|
||||
converted_tolerance = cls.get_converted_tolerance(tolerance_si=0.03)
|
||||
poly = poly.buffer(
|
||||
converted_tolerance,
|
||||
single_sided=True,
|
||||
@@ -597,8 +591,10 @@ class Spatial(blenderbim.core.tool.Spatial):
|
||||
bm.edges.index_update()
|
||||
|
||||
mat_invert = mat.inverted()
|
||||
|
||||
new_verts = [bm.verts.new(mat_invert @ Vector([v[0], v[1], 0])) for v in poly.exterior.coords[0:-1]]
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
new_verts = [
|
||||
bm.verts.new(mat_invert @ (Vector([v[0], v[1], 0]) * si_conversion)) for v in poly.exterior.coords[0:-1]
|
||||
]
|
||||
[bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)]
|
||||
bm.edges.new((new_verts[len(new_verts) - 1], new_verts[0]))
|
||||
|
||||
|
||||
@@ -8,7 +8,36 @@ Scenario: Execute generate flooring coverings from walls
|
||||
And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType"
|
||||
And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()"
|
||||
And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}"
|
||||
# 1st wall
|
||||
And I press "bim.add_constr_type_instance"
|
||||
And the object "IfcWall/Wall" is selected
|
||||
When I press "bim.add_instance_flooring_coverings_from_walls"
|
||||
Then nothing happens
|
||||
And I press "bim.change_layer_length(length=3.6)"
|
||||
# 2nd wall
|
||||
And the cursor is at "3.6,0.1,3"
|
||||
And I set "scene.BIMModelProperties.length" to "2.0"
|
||||
And I press "bim.add_constr_type_instance"
|
||||
# 3rd wall
|
||||
And the cursor is at "3.5,2.1,3"
|
||||
And I set "scene.BIMModelProperties.length" to "3.5"
|
||||
And I press "bim.add_constr_type_instance"
|
||||
# 4th wall
|
||||
And the cursor is at "0,2.0,0"
|
||||
And I set "scene.BIMModelProperties.length" to "1.9"
|
||||
And I press "bim.add_constr_type_instance"
|
||||
# add_instance_flooring_coverings_from_walls is expecting FLOORING predefined type.
|
||||
And the object "IfcCoveringType/COV30" is selected
|
||||
And I press "bim.enable_editing_attributes(obj='IfcCoveringType/COV30')"
|
||||
And I set "active_object.BIMAttributeProperties.attributes[6].enum_value" to "FLOORING"
|
||||
And I press "bim.edit_attributes(obj='IfcCoveringType/COV30')"
|
||||
# Run the operator.
|
||||
When the object "IfcWall/Wall" is selected
|
||||
And additionally the object "IfcWall/Wall.001" is selected
|
||||
And additionally the object "IfcWall/Wall.002" is selected
|
||||
And additionally the object "IfcWall/Wall.003" is selected
|
||||
And I set "scene.BIMModelProperties.ifc_class" to "IfcCoveringType"
|
||||
And the variable "element_type" is "[e for e in {ifc}.by_type('IfcCoveringType') if e.Name == 'COV30'][0].id()"
|
||||
And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}"
|
||||
And I press "bim.add_instance_flooring_coverings_from_walls"
|
||||
Then the object "IfcCovering/Covering0" exists
|
||||
And the object "IfcCovering/Covering0" is at "1.8,1.05,0.0"
|
||||
And the object "IfcCovering/Covering0" dimensions are "3.4,1.9,0.03"
|
||||
|
||||
Reference in New Issue
Block a user