Remove claude

This commit is contained in:
Dion Moult
2026-01-21 12:32:11 +11:00
parent 22fd318d21
commit b86bf45167
2 changed files with 0 additions and 647 deletions
-10
View File
@@ -1,10 +0,0 @@
{
"permissions": {
"allow": [
"Bash(cat:*)",
"Bash(find:*)",
"Bash(grep:*)",
"Bash(xargs:*)"
]
}
}
-637
View File
@@ -1,637 +0,0 @@
# CLAUDE.md - Saikei Civil Context for IfcOpenShell Contributions
> This document provides context for Claude Code when working on Saikei Civil contributions to IfcOpenShell, specifically horizontal alignment visualization.
---
## Project Overview
**Saikei Civil** (formerly BlenderCivil) is an open-source Blender extension for native IFC 4.3 infrastructure design. The project aims to democratize professional civil engineering tools by providing free alternatives to expensive commercial software like Civil 3D ($2,500/year) and OpenRoads ($4,000/year).
### Mission
- **Bonsai BIM** = Buildings (vertical construction)
- **Saikei Civil** = Infrastructure (horizontal construction: roads, earthwork, drainage)
> "While Bonsai crafts the buildings, Saikei shapes the world around them."
### Key Differentiator
**Native IFC Philosophy**: IFC files serve as the primary database rather than export targets. We're not converting TO IFC - we ARE IFC from the start.
---
## Architecture Principles
### Three-Layer Architecture (Matches Bonsai)
Saikei follows Bonsai's proven architecture with `core/` and `tool/` at the **package root level**:
```
saikei/
├── core/ # Layer 1: Pure Python - NO bpy imports
│ └── alignment.py # Business logic, math, validation
├── tool/ # Layer 2: Blender implementations - HAS bpy
│ └── alignment.py # Blender object creation, linking
└── civil/ # Layer 3: UI (like Bonsai's bim/)
└── module/
└── alignment/
├── __init__.py # Registration
├── operator.py # Blender operators
├── ui.py # UI panels
├── prop.py # PropertyGroups
└── data.py # UI data caching
```
**Layer Responsibilities:**
```
┌─────────────────────────────────────────────────────────────┐
│ Layer 3: civil/module/{name}/ (UI Layer) │
│ - operator.py: User actions (bpy.types.Operator) │
│ - ui.py: Interface panels (bpy.types.Panel) │
│ - prop.py: UI state (bpy.types.PropertyGroup) │
│ - Calls core functions, passing tool implementations │
└─────────────────────────────────────────────────────────────┘
│ calls
┌─────────────────────────────────────────────────────────────┐
│ Layer 1: core/ (Pure Python - NO bpy imports) │
│ - All business logic, algorithms, mathematics │
│ - Receives tool classes as parameters (dependency inject) │
│ - MUST be testable outside Blender │
└─────────────────────────────────────────────────────────────┘
│ receives as parameters
┌─────────────────────────────────────────────────────────────┐
│ Layer 2: tool/ (Blender implementations) │
│ - Concrete implementations with bpy │
│ - Blender object creation, scene manipulation │
│ - Wraps Bonsai's tool.Ifc, tool.Collector, etc. │
└─────────────────────────────────────────────────────────────┘
```
### Bonsai's Dependency Injection Pattern
Core functions receive tool classes as parameters, enabling testability:
```python
# In core/alignment.py (NO bpy imports)
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import ifcopenshell
import saikei.tool as tool
def create_alignment_visualization(
ifc: type[tool.Ifc],
alignment_tool: type[tool.Alignment],
alignment: ifcopenshell.entity_instance,
) -> list:
"""Pure business logic - tools passed as parameters."""
segments = get_layout_segments(alignment)
objects = []
for segment in segments:
obj = alignment_tool.create_segment_object(segment)
ifc.link(obj, segment)
objects.append(obj)
return objects
```
```python
# In civil/module/alignment/operator.py (HAS bpy)
import bpy
import saikei.tool as tool
import saikei.core.alignment as core
class SAIKEI_OT_visualize_alignment(bpy.types.Operator):
def execute(self, context):
alignment = self.get_active_alignment()
# Call core logic, passing tool implementations
core.create_alignment_visualization(
tool.Ifc, tool.Alignment, alignment
)
return {'FINISHED'}
```
### Golden Pattern for Native IFC
```python
# 1. GET IFC FILE
ifc = NativeIfcManager.get_file()
# 2. CREATE/MODIFY IFC ENTITY FIRST
entity = ifc.create_entity("IfcAlignment", ...)
# 3. CREATE BLENDER VISUALIZATION SECOND
obj = create_blender_object(...)
# 4. LINK THEM (minimal storage in Blender)
NativeIfcManager.link_object(obj, entity)
# obj["ifc_definition_id"] = entity.id()
# obj["ifc_class"] = entity.is_a()
# obj["GlobalId"] = entity.GlobalId
# 5. SAVE = WRITE IFC FILE
NativeIfcManager.save_file("project.ifc")
```
### Key Principles
1. **IFC-First Design**: ALL civil engineering data lives in the IFC file
2. **Minimal Blender Storage**: Only 3 properties stored in Blender objects
3. **Separation of Concerns**: Core logic has NO bpy imports
4. **IfcStore Pattern**: Following Bonsai's proven pattern for IFC file management
---
## IFC 4.3 Alignment Structure
### Entity Hierarchy
```
IfcProject
└── IfcSite
└── IfcRoad (via IfcRelAggregates)
└── IfcAlignment (via IfcRelContainedInSpatialStructure)
├── IfcAlignmentHorizontal (via IfcRelNests)
│ └── [IfcAlignmentSegment → IfcAlignmentHorizontalSegment]*
├── IfcAlignmentVertical (via IfcRelNests)
│ └── [IfcAlignmentSegment → IfcAlignmentVerticalSegment]*
└── IfcAlignmentCant (via IfcRelNests) [Future]
└── [IfcAlignmentSegment → IfcAlignmentCantSegment]*
```
### Critical IFC Rules
1. **Zero-Length Terminal Segments**: The last `IfcAlignmentSegment.DesignParameters` in each layout MUST be zero length to provide the end point
2. **Ordered Collections**: `IfcRelNests.RelatedObjects` maintains segment order (start to end)
3. **Nesting Order**: Horizontal precedes Vertical precedes Cant in `IfcRelNests`
### Semantic vs Geometric Representation
The IFC 4.3 alignment model has TWO parallel structures:
**Semantic (Business Logic)**:
- `IfcAlignmentHorizontalSegment` with `PredefinedType` (LINE, CIRCULARARC, CLOTHOID, etc.)
- Contains design parameters (radius, length, direction)
**Geometric (Shape)**:
- `IfcCurveSegment``ParentCurve` (IfcLine, IfcCircle, IfcClothoid)
- Combined into `IfcCompositeCurve` (horizontal) or `IfcGradientCurve` (vertical)
**Mapping Table:**
| Business Logic (Semantic) | Geometric ParentCurve |
|---------------------------|----------------------|
| LINE | IfcLine |
| CIRCULARARC | IfcCircle |
| CLOTHOID | IfcClothoid |
| CUBIC | IfcPolynomialCurve |
| PARABOLICARC | IfcPolynomialCurve |
| CONSTANTGRADIENT | IfcLine |
### The 2.5D Layered Model
IFC alignments use a "2.5D" approach - combining multiple 2D curves:
1. **Layer 1 - Horizontal**: `IfcCompositeCurve` in X-Y (Easting-Northing) plane
2. **Layer 2 - Vertical**: `IfcGradientCurve` in "Distance Along, Elevation" coordinate system
- `BaseCurve` attribute points to horizontal `IfcCompositeCurve`
3. **Layer 3 - Cant**: `IfcSegmentedReferenceCurve` for superelevation
- `BaseCurve` typically points to `IfcGradientCurve`
---
## Horizontal Alignment Implementation
### PI-Driven Design Approach
Saikei Civil uses the **Point of Intersection (PI)** method, matching professional workflows in Civil 3D and OpenRoads:
```
PI● is just an intersection point
╲ Tangent
BC (Begin Curve)
● Curve (R=150m)
EC (End Curve)
Tangent
```
**Key Distinction**:
- PIs are just intersection points (NO radius property)
- Curves are separate entities inserted between tangents (Curves HAVE radius)
### Core Classes
```python
class HorizontalAlignmentManager:
"""Core engine for horizontal alignment"""
def add_pi(self, x: float, y: float) -> PI
def insert_curve(self, pi_index: int, radius: float) -> Curve
def generate_segments(self) -> List[Segment]
class PI:
"""Point of Intersection - just a position"""
position: Tuple[float, float]
# NO radius property
class Curve:
"""Curve inserted at a PI"""
radius: float
bc: Tuple[float, float] # Begin Curve point
ec: Tuple[float, float] # End Curve point
at_pi: int # Which PI this curve is at
```
### Civil Engineering Mathematics
**Deflection Angle:**
```
Δ = arccos(t₁ · t₂)
```
Where t₁ and t₂ are normalized incoming/outgoing tangent vectors.
**Tangent Length:**
```
T = R × tan(Δ/2)
```
**Arc Length:**
```
L = R × Δ (radians)
```
**BC/EC Points:**
```
BC = PI - t₁ × T
EC = PI + t₂ × T
```
### Segment Generation
```python
def regenerate_segments(self):
"""Auto-generate tangent and curve segments from PIs"""
segments = []
for i, pi in enumerate(self.pis[:-1]):
next_pi = self.pis[i + 1]
# Check if curve at this PI
curve = self.get_curve_at_pi(i)
if curve:
# Add incoming tangent (trimmed to BC)
segments.append(create_line_segment(prev_end, curve.bc))
# Add curve
segments.append(create_arc_segment(curve))
prev_end = curve.ec
else:
# Add full tangent
segments.append(create_line_segment(prev_end, next_pi.position))
prev_end = next_pi.position
return segments
```
---
## Visualization Layer
### AlignmentVisualizer Class
```python
class AlignmentVisualizer:
"""Create Blender visualization of IFC alignment"""
def __init__(self, native_alignment):
self.alignment = native_alignment
self.collection = None
self.pi_objects = []
self.segment_objects = []
def visualize_all(self):
"""Generate complete visualization"""
self.setup_collection()
self.create_pi_markers()
self.create_segment_curves()
```
### Color Coding Convention
**PI Markers (Empties):**
- 🟢 Green = Tangent points (no curve)
- 🟠 Orange = Curve PIs (curve inserted)
**Segment Objects (Curves):**
- 🔵 Blue = Tangent segments (LINE)
- 🔴 Red = Circular arcs (CIRCULARARC)
### Object Linking Pattern
```python
# Every Blender object stores only 3 properties
obj["ifc_definition_id"] = entity.id()
obj["ifc_class"] = entity.is_a()
obj["GlobalId"] = entity.GlobalId
# All other data comes from IFC
entity = NativeIfcManager.get_entity(obj)
params = entity.DesignParameters # Real data from IFC!
```
---
## Rick Brice's IfcOpenShell Alignment API
Rick Brice's alignment API was merged into IfcOpenShell v0.8.0 (PR #6234, March 14, 2025). This API provides comprehensive Python functions for IFC alignment creation.
### Key Functions
**Creation:**
```python
import ifcopenshell.api.alignment as align_api
# Create alignment with PI method
alignment = align_api.create_by_pi_method(
ifc_file,
name='Main Alignment',
hpoints=[(0,0), (100,50), (200,100)], # Horizontal PI coordinates
radii=[0, 150, 200], # Curve radii at PIs
start_station=0.0
)
# Create alignment structure
alignment = align_api.create(
ifc_file,
name="Highway 101",
horizontal_layout=horiz,
vertical_layout=vert # Optional
)
```
**Layout Functions:**
```python
# Add to existing horizontal
align_api.layout_horizontal_alignment_by_pi_method(
ifc_file, horiz_alignment, hpoints, radii
)
# Add vertical layout
align_api.add_vertical_layout(alignment, vertical_layout)
# Add zero-length terminator (required!)
align_api.add_zero_length_segment(layout)
```
**Getters:**
```python
horiz = align_api.get_horizontal_layout(alignment)
vert = align_api.get_vertical_layout(alignment)
segments = align_api.get_layout_segments(layout)
curve = align_api.get_layout_curve(layout) # IfcCompositeCurve/IfcGradientCurve
```
### Integration Strategy
**Recommended architecture for Saikei contributions:**
| Layer | Rick's API Responsibility | Saikei's Responsibility |
|-------|--------------------------|------------------------|
| IFC Backend | All IFC entity creation, relationships, geometric representations | None - use Rick's API |
| Business Logic | Alignment math, segment generation, stationing | Design validation, AASHTO rules |
| UI Layer | None (Python API only) | Full Blender panels, operators |
| Visualization | None | Real-time 3D preview, PI markers |
### Example Integration Pattern
```python
# Saikei Civil operator using Rick's API backend
import ifcopenshell.api.alignment as align_api
class SAIKEI_OT_create_alignment(bpy.types.Operator):
def execute(self, context):
# Get PI data from Blender UI
hpoints = [(pi.x, pi.y) for pi in context.scene.saikei_pis]
radii = [pi.radius for pi in context.scene.saikei_pis]
# Use Rick's API for IFC creation
alignment = align_api.create_by_pi_method(
self.ifc_file,
name='Main Alignment',
hpoints=hpoints,
radii=radii,
start_station=context.scene.saikei_start_station
)
# Saikei handles visualization
self.visualizer.update_from_ifc(alignment)
return {'FINISHED'}
```
---
## Validation and Compliance
### buildingSMART Validation
Saikei Civil has undergone extensive validation testing with buildingSMART International. Key compliance requirements:
1. **Zero-Length Terminal Segments**: Every layout must end with a zero-length segment
2. **Spatial Hierarchy**: Proper `IfcRelAggregates` and `IfcRelContainedInSpatialStructure`
3. **Segment Continuity**: End of segment N must match start of segment N+1 (< 0.001m tolerance)
4. **Ordered Nesting**: Segments in correct order via `IfcRelNests.RelatedObjects`
### Validation Code Pattern
```python
def validate_alignment(alignment):
"""Validate IFC alignment structure"""
errors = []
warnings = []
# Check basic structure
if not alignment:
errors.append("No IfcAlignment entity")
return errors, warnings
# Get horizontal layout
horiz = get_horizontal_layout(alignment)
if not horiz:
errors.append("No IfcAlignmentHorizontal")
return errors, warnings
# Check segments
segments = get_layout_segments(horiz)
if len(segments) < 2:
warnings.append("Need at least 2 segments")
# Check zero-length terminator
last_seg = segments[-1].DesignParameters
if last_seg.SegmentLength > 0.0001:
errors.append("Missing zero-length terminal segment")
# Check continuity
for i in range(len(segments) - 1):
gap = calculate_gap(segments[i], segments[i+1])
if gap > 0.001:
errors.append(f"Gap of {gap}m between segments {i} and {i+1}")
return errors, warnings
```
---
## PR Focus: Horizontal Alignment Visualization
For your first PR focused on horizontal alignment visualization, focus on:
### Core Requirements
1. **Read IFC alignment data** using Rick's API getters
2. **Generate Blender visualization objects** (curves/empties)
3. **Link objects to IFC entities** with minimal storage
4. **Color-code by segment type** (LINE=blue, CIRCULARARC=red)
5. **Support real-time updates** via depsgraph handlers
### Key Files to Create/Modify
Following Bonsai's architecture with `core/` and `tool/` at package root:
```
saikei/
├── core/ # NEW - Pure Python (NO bpy)
│ ├── __init__.py
│ └── alignment.py # Business logic, math, validation
├── tool/ # NEW - Blender implementations
│ ├── __init__.py
│ └── alignment.py # Blender object creation, linking
└── civil/ # EXISTING - UI layer
└── module/
└── alignment/
├── __init__.py # Registration
├── operator.py # Operators call core.*, passing tool.*
├── ui.py # UI panels
├── prop.py # PropertyGroups
└── data.py # UI data caching
```
### Minimal Visualization Implementation
```python
def visualize_horizontal_alignment(alignment, collection):
"""Create Blender visualization from IFC alignment"""
# Get segments from IFC
horiz = align_api.get_horizontal_layout(alignment)
segments = align_api.get_layout_segments(horiz)
objects = []
for i, segment in enumerate(segments):
params = segment.DesignParameters
if params.PredefinedType == "LINE":
obj = create_line_curve(params, name=f"Tangent_{i}")
set_material_color(obj, BLUE)
elif params.PredefinedType == "CIRCULARARC":
obj = create_arc_curve(params, name=f"Curve_{i}")
set_material_color(obj, RED)
# Link to IFC
obj["ifc_definition_id"] = segment.id()
obj["ifc_class"] = segment.is_a()
obj["GlobalId"] = segment.GlobalId
collection.objects.link(obj)
objects.append(obj)
return objects
```
---
## Development Guidelines
### Code Style
- Follow PEP 8
- Type annotations for all public functions
- Docstrings with examples
- No `bpy` imports in `core/` modules
### Testing
- Unit tests for all core logic (outside Blender)
- Integration tests with sample IFC files
- Validation against buildingSMART checker
### Commit Messages
```
feat(alignment): Add horizontal alignment visualization
- Create AlignmentVisualizer class for Blender curve generation
- Support LINE and CIRCULARARC segment types
- Implement IFC entity linking pattern
- Add color coding by segment type
Refs: #123
```
---
## Resources
### Documentation
- IFC 4.3 Specification: https://ifc43-docs.standards.buildingsmart.org/
- IfcOpenShell Docs: https://docs.ifcopenshell.org/
- Bonsai Wiki: https://wiki.osarch.org/
### Community
- OSArch Forum: https://community.osarch.org/
- IfcOpenShell GitHub: https://github.com/IfcOpenShell/IfcOpenShell
- buildingSMART Forums: https://forums.buildingsmart.org/
### Key Contacts
- **Rick Brice** (WSDOT) - IfcOpenShell alignment API author
- **Dion Moult** - Bonsai BIM founder
- **Will Sharp** (HDR) - buildingSMART committee co-chair
---
## Quick Reference
### Entity Creation Pattern
```python
# Always create IFC first, then Blender, then link
entity = ifc.create_entity("IfcAlignmentSegment", ...)
obj = bpy.data.objects.new("Segment", curve_data)
obj["ifc_definition_id"] = entity.id()
```
### Segment Types
- `LINE` → IfcLine (blue visualization)
- `CIRCULARARC` → IfcCircle (red visualization)
- `CLOTHOID` → IfcClothoid (future)
- `CONSTANTGRADIENT` → IfcLine (vertical)
- `PARABOLICARC` → IfcPolynomialCurve (vertical)
### Required Terminal Segment
```python
# Last segment MUST be zero-length
align_api.add_zero_length_segment(layout)
```
### Minimal Object Storage
```python
# ONLY these 3 properties in Blender
obj["ifc_definition_id"] = entity.id()
obj["ifc_class"] = entity.is_a()
obj["GlobalId"] = entity.GlobalId
```
---
*Document Version: 1.1*
*Updated: January 2026*
*Changes: Updated architecture to match Bonsai's actual pattern (core/ and tool/ at package root)*
*For: Saikei Civil IfcOpenShell PR - Horizontal Alignment Visualization*