mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 10:57:49 +00:00
Hide zero-length terminator segments from UI and suppress empty alignment warnings
Zero-length segments are required by IFC to mark alignment ends but should be invisible to users. This change: - Adds helper methods to detect zero-length and empty layouts - Silently skips geometry generation for empty alignments (no error messages) - Excludes zero-length segments from Outliner display - Uses separate visible segment counter for consistent naming Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -196,6 +196,57 @@ class Alignment:
|
||||
|
||||
return ((bc_x, bc_y), (ec_x, ec_y))
|
||||
|
||||
# =========================================================================
|
||||
# Zero-Length Segment Utilities
|
||||
# =========================================================================
|
||||
|
||||
@classmethod
|
||||
def is_zero_length_segment(cls, segment: "ifcopenshell.entity_instance") -> bool:
|
||||
"""Check if a segment is a zero-length terminator segment.
|
||||
|
||||
Zero-length segments are required by IFC to mark the end of an alignment
|
||||
but should be invisible to users in the UI.
|
||||
|
||||
Args:
|
||||
segment: The IfcAlignmentSegment entity
|
||||
|
||||
Returns:
|
||||
True if this is a zero-length segment
|
||||
"""
|
||||
if not hasattr(segment, "DesignParameters") or not segment.DesignParameters:
|
||||
return False
|
||||
|
||||
dp = segment.DesignParameters
|
||||
|
||||
# Check based on segment type
|
||||
if dp.is_a("IfcAlignmentHorizontalSegment"):
|
||||
return abs(dp.SegmentLength) < 1e-6
|
||||
elif dp.is_a("IfcAlignmentVerticalSegment"):
|
||||
return abs(dp.HorizontalLength) < 1e-6
|
||||
elif dp.is_a("IfcAlignmentCantSegment"):
|
||||
return abs(dp.HorizontalLength) < 1e-6
|
||||
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def layout_has_real_segments(cls, layout: "ifcopenshell.entity_instance") -> bool:
|
||||
"""Check if a layout has any real (non-zero-length) segments.
|
||||
|
||||
An empty layout only has the mandatory zero-length terminator segment.
|
||||
|
||||
Args:
|
||||
layout: The IFC layout entity (IfcAlignmentHorizontal, etc.)
|
||||
|
||||
Returns:
|
||||
True if the layout has at least one real segment
|
||||
"""
|
||||
for rel in getattr(layout, "IsNestedBy", []) or []:
|
||||
for segment in rel.RelatedObjects or []:
|
||||
if segment.is_a("IfcAlignmentSegment"):
|
||||
if not cls.is_zero_length_segment(segment):
|
||||
return True
|
||||
return False
|
||||
|
||||
# =========================================================================
|
||||
# Blender Object Creation
|
||||
# =========================================================================
|
||||
@@ -290,18 +341,24 @@ class Alignment:
|
||||
is configured (for handling large geospatial coordinates), the vertices
|
||||
are transformed to Blender local coordinates.
|
||||
|
||||
Empty alignments (only zero-length terminator segment) are silently skipped.
|
||||
|
||||
Args:
|
||||
layout: The IFC layout entity (IfcAlignmentHorizontal, etc.)
|
||||
parent_obj: The parent Blender object (alignment object)
|
||||
|
||||
Returns:
|
||||
The created Blender curve object, or None if no representation
|
||||
The created Blender curve object, or None if no representation or empty
|
||||
"""
|
||||
import ifcopenshell.api.alignment as align_api
|
||||
from ifcopenshell.api.alignment import util as align_util
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
# Skip empty layouts (only zero-length terminator) - no error message needed
|
||||
if not cls.layout_has_real_segments(layout):
|
||||
return None
|
||||
|
||||
# Get the layout's curve representation
|
||||
try:
|
||||
rep_curve = align_api.get_layout_curve(layout)
|
||||
@@ -397,14 +454,22 @@ class Alignment:
|
||||
Creates an empty (no geometry) for segment selection/editing.
|
||||
The layout curve handles visualization.
|
||||
|
||||
Zero-length segments (required terminators) are skipped as they should
|
||||
be invisible to users.
|
||||
|
||||
Args:
|
||||
segment: The IfcAlignmentSegment entity
|
||||
index: The segment index (for naming)
|
||||
parent_obj: The parent Blender object (layout object)
|
||||
|
||||
Returns:
|
||||
The created Blender object, or existing one if already linked
|
||||
The created Blender object, or existing one if already linked,
|
||||
or None for zero-length segments
|
||||
"""
|
||||
# Skip zero-length segments - they are required terminators but should be invisible
|
||||
if cls.is_zero_length_segment(segment):
|
||||
return None
|
||||
|
||||
# Check if a Blender object already exists for this IFC element
|
||||
existing_obj = tool.Ifc.get_object(segment)
|
||||
if existing_obj:
|
||||
@@ -508,12 +573,18 @@ class Alignment:
|
||||
result_objs.append(curve_obj)
|
||||
|
||||
# Create empty objects for each segment (for selection/editing)
|
||||
# Use a separate counter for visible segments to ensure consistent numbering
|
||||
visible_index = 0
|
||||
for rel in getattr(layout, "IsNestedBy", []) or []:
|
||||
for i, segment in enumerate(rel.RelatedObjects or []):
|
||||
for segment in rel.RelatedObjects or []:
|
||||
if segment.is_a() == "IfcAlignmentSegment":
|
||||
seg_obj = cls._create_segment_empty(segment, i, layout_obj)
|
||||
# Skip zero-length segments (they are invisible terminators)
|
||||
if cls.is_zero_length_segment(segment):
|
||||
continue
|
||||
seg_obj = cls._create_segment_empty(segment, visible_index, layout_obj)
|
||||
if seg_obj:
|
||||
result_objs.append(seg_obj)
|
||||
visible_index += 1 # Always increment for consistent numbering
|
||||
|
||||
return result_objs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user