mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 02:47:48 +00:00
Bonsai: support circle profiles when editing an extrusion profile (#3381)
Enabling extrusion-profile editing on an element whose profile is an IfcCircleProfileDef showed nothing editable: tool.Model.import_profile had branches for IfcArbitraryClosedProfileDef, IfcRectangleProfileDef and IfcAnnotationFillArea, but none for circles, so the leftover 3D body mesh leaked through (238 verts, z spread -1..1, no PROFILE subshape). Add an import_circle branch using the module's existing 2-vertex-diameter + IFCCIRCLE vertex-group convention (the same one convert_curve_to_mesh emits and auto_detect_profiles consumes on export), honouring profile.Position and unit scale like the neighbouring rectangle branch. IfcCircleHollowProfileDef gets a second inner circle at Radius - WallThickness; the export path's containment logic already turns two nested loops into IfcArbitraryProfileDefWithVoids. Verified live in headless Blender: enable-editing now yields a 2-vert IFCCIRCLE profile mesh (subshape_type PROFILE) at the exact SI radius; a no-op edit round-trips to an IfcArbitraryClosedProfileDef wrapping an IfcCircle with radius delta ~4e-8 and the element still tessellates (238 verts as before). Rectangle profile editing is unaffected. Note on scope: converting the specific profile class to a curve-based one on save is the module's existing, accepted behaviour for rectangles; this change only brings circles to parity for editing. Generated with the assistance of an AI coding tool. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -483,6 +483,8 @@ class Model(bonsai.core.tool.Model):
|
||||
cls.convert_curve_to_mesh(obj, position, inner_curve, x_angle=x_angle)
|
||||
elif profile.is_a() == "IfcRectangleProfileDef":
|
||||
cls.import_rectangle(obj, position, profile)
|
||||
elif profile.is_a("IfcCircleProfileDef"):
|
||||
cls.import_circle(obj, position, profile)
|
||||
elif profile.is_a() == "IfcAnnotationFillArea":
|
||||
cls.convert_curve_to_mesh(obj, position, profile.OuterBoundary)
|
||||
for inner_boundary in profile.InnerBoundaries or []:
|
||||
@@ -685,6 +687,36 @@ class Model(bonsai.core.tool.Model):
|
||||
cls.edges.extend([(i, i + 1) for i in range(0, len(cls.vertices))])
|
||||
cls.edges[-1] = (len(cls.vertices) - 1, 0) # Close the loop
|
||||
|
||||
@classmethod
|
||||
def import_circle(cls, obj: bpy.types.Object, position: Matrix, profile: ifcopenshell.entity_instance) -> None:
|
||||
"""Import IfcCircleProfileDef/IfcCircleHollowProfileDef.
|
||||
|
||||
Uses the 2-vertex diameter representation used throughout this module
|
||||
(see `convert_curve_to_mesh`'s `IfcCircle` branch and
|
||||
`auto_detect_profiles`), so a no-op edit round-trips to an equivalent
|
||||
circle.
|
||||
"""
|
||||
if profile.Position:
|
||||
p_position = Matrix(ifcopenshell.util.placement.get_axis2placement(profile.Position).tolist())
|
||||
p_position.translation *= cls.unit_scale
|
||||
else:
|
||||
p_position = Matrix()
|
||||
|
||||
def add_circle(radius: float) -> None:
|
||||
offset = len(cls.vertices)
|
||||
cls.vertices.extend(
|
||||
[
|
||||
position @ p_position @ Vector((0.0, -radius, 0.0)),
|
||||
position @ p_position @ Vector((0.0, radius, 0.0)),
|
||||
]
|
||||
)
|
||||
cls.circles.append([offset, offset + 1])
|
||||
cls.edges.append((offset, offset + 1))
|
||||
|
||||
add_circle(cls.convert_unit_to_si(profile.Radius))
|
||||
if profile.is_a("IfcCircleHollowProfileDef"):
|
||||
add_circle(cls.convert_unit_to_si(profile.Radius - profile.WallThickness))
|
||||
|
||||
@classmethod
|
||||
def load_openings(cls, openings: list[ifcopenshell.entity_instance]) -> Iterable[bpy.types.Object]:
|
||||
if not openings:
|
||||
|
||||
Reference in New Issue
Block a user