User Plane Demo#

Demonstration of User Plane services in Dips Python API.

This script demonstrates IUserPlaneServices methods including: - AddUserPlane: Create a new user-defined plane - GetUserPlaneList: List all user planes - DeleteUserPlane: Remove a user plane

Code Snippet: UserPlaneDemo.py#
"""
Demonstration of User Plane services in Dips Python API.

This script demonstrates IUserPlaneServices methods including:
- AddUserPlane: Create a new user-defined plane
- GetUserPlaneList: List all user planes
- DeleteUserPlane: Remove a user plane
"""

import math
from dips import DipsApp
from dips import DipsAPI_pb2

import dips.PlaneEntityInfoVal
import dips.PlaneVal
import dips.TrendPlungeVal
import dips.AngleDataVal
import dips.ColorSurrogateVal


# =============================================================================
# HELPER FUNCTIONS
# =============================================================================

def create_trend_plunge(trend_deg: float, plunge_deg: float):
    """Create a TrendPlunge from degrees."""
    tp = dips.TrendPlungeVal.TrendPlungeVal()
    tp.trend = dips.AngleDataVal.AngleDataVal()
    tp.trend.angle_radians = math.radians(trend_deg)
    tp.plunge = dips.AngleDataVal.AngleDataVal()
    tp.plunge.angle_radians = math.radians(plunge_deg)
    return tp


def create_color(r: int, g: int, b: int, a: int = 255):
    """Create a Color from RGBA values."""
    color = dips.ColorSurrogateVal.ColorSurrogateVal()
    color.r = r
    color.g = g
    color.b = b
    color.a = a
    return color


# =============================================================================
# USER PLANE DEMONSTRATIONS
# =============================================================================

def demonstrate_add_user_plane(model):
    """Demonstrate adding a user plane."""
    print("\n" + "=" * 60)
    print("ADD USER PLANE")
    print("=" * 60)
    
    try:
        # Create the Plane object with orientation data
        plane_data = dips.PlaneVal.PlaneVal()
        plane_data.id = "Slope Face"
        plane_data.pole = create_trend_plunge(180, 45)  # 45° dip to the south
        
        # Create the PlaneEntityInfo wrapper with color
        plane_info = dips.PlaneEntityInfoVal.PlaneEntityInfoVal()
        plane_info.color = create_color(255, 0, 0)  # Red
        plane_info.plane = plane_data
        
        result = model.AddUserPlane(plane_info)
        print(f"  ✓ AddUserPlane: '{plane_data.id}'")
        print(f"    Orientation: Trend=180°, Plunge=45°")
        print(f"    (Represents a plane dipping 45° to the south)")
        return result
    except Exception as e:
        print(f"  ✗ AddUserPlane: {e}")
        return None


def demonstrate_get_user_plane_list(model):
    """Demonstrate listing all user planes."""
    print("\n" + "=" * 60)
    print("GET USER PLANE LIST")
    print("=" * 60)
    
    try:
        planes = model.GetUserPlaneList()
        print(f"  ✓ GetUserPlaneList: {len(planes)} plane(s) found")
        
        for i, plane_ref in enumerate(planes):
            plane_value = plane_ref.GetValue()
            plane_data = plane_value.plane
            trend = math.degrees(plane_data.pole.trend.angle_radians)
            plunge = math.degrees(plane_data.pole.plunge.angle_radians)
            print(f"    [{i+1}] ID: '{plane_data.id}'")
            print(f"        Pole: Trend={trend:.1f}°, Plunge={plunge:.1f}°")
        
        return planes
    except Exception as e:
        print(f"  ✗ GetUserPlaneList: {e}")
        return []


def demonstrate_delete_user_plane(model, plane_ref):
    """Demonstrate deleting a user plane."""
    print("\n" + "=" * 60)
    print("DELETE USER PLANE")
    print("=" * 60)
    
    if plane_ref is None:
        print("  - DeleteUserPlane: No plane to delete")
        return
    
    try:
        plane_value = plane_ref.GetValue()
        plane_id = plane_value.plane.id
        model.DeleteUserPlane(plane_ref)
        print(f"  ✓ DeleteUserPlane: '{plane_id}'")
    except Exception as e:
        print(f"  ✗ DeleteUserPlane: {e}")


def demonstrate_multiple_user_planes(model):
    """Demonstrate creating multiple user planes for geological features."""
    print("\n" + "=" * 60)
    print("MULTIPLE USER PLANE EXAMPLES")
    print("=" * 60)
    
    # Common geological planes to define
    plane_examples = [
        ("Pit Wall - North", 0, 60, (255, 0, 0)),      # North-dipping wall
        ("Pit Wall - East", 90, 55, (0, 255, 0)),      # East-dipping wall
        ("Pit Wall - South", 180, 50, (0, 0, 255)),    # South-dipping wall
        ("Pit Wall - West", 270, 65, (255, 255, 0)),   # West-dipping wall
        ("Fault Plane", 135, 70, (255, 0, 255)),       # SE-dipping fault
        ("Bedding Plane", 45, 25, (0, 255, 255)),      # NE-dipping bedding
    ]
    
    created_planes = []
    
    for plane_id, trend, plunge, color_rgb in plane_examples:
        try:
            # Create the Plane object with orientation data
            plane_data = dips.PlaneVal.PlaneVal()
            plane_data.id = plane_id
            plane_data.pole = create_trend_plunge(trend, plunge)
            
            # Create the PlaneEntityInfo wrapper with color
            plane_info = dips.PlaneEntityInfoVal.PlaneEntityInfoVal()
            plane_info.color = create_color(*color_rgb)
            plane_info.plane = plane_data
            
            result = model.AddUserPlane(plane_info)
            created_planes.append(result)
            print(f"  ✓ Created: '{plane_id}' (Pole: {trend}°/{plunge}°)")
        except Exception as e:
            print(f"  ✗ Failed to create '{plane_id}': {e}")
    
    return created_planes


def demonstrate_cleanup(model, planes_to_delete):
    """Clean up created planes."""
    print("\n" + "=" * 60)
    print("CLEANUP")
    print("=" * 60)
    
    for plane_ref in planes_to_delete:
        try:
            plane_value = plane_ref.GetValue()
            model.DeleteUserPlane(plane_ref)
            print(f"  ✓ Deleted: '{plane_value.plane.id}'")
        except Exception as e:
            print(f"  ✗ Delete failed: {e}")


# =============================================================================
# MAIN
# =============================================================================

def main():
    """Main demonstration function."""
    print("=" * 60)
    print("Dips API - User Plane Services Demo")
    print("=" * 60)
    
    # Connect to Dips
    print("\nConnecting to Dips application...")
    try:
        app = DipsApp.LaunchApp(62535)
        print("✓ Connected to Dips")
    except Exception as e:
        print(f"✗ Failed to connect: {e}")
        print("Make sure Dips is running with scripting enabled on port 62535")
        return
    
    model = app.GetModel()
    
    # Show initial state
    print("\n" + "-" * 60)
    print("INITIAL STATE")
    print("-" * 60)
    demonstrate_get_user_plane_list(model)
    
    # Add a single user plane
    new_plane = demonstrate_add_user_plane(model)
    
    # List planes again
    demonstrate_get_user_plane_list(model)
    
    # Delete the plane
    demonstrate_delete_user_plane(model, new_plane)
    
    # Create multiple planes
    created_planes = demonstrate_multiple_user_planes(model)
    
    # List all planes
    demonstrate_get_user_plane_list(model)
    
    # Cleanup (commented out to keep planes visible)
    # demonstrate_cleanup(model, created_planes)
    
    # Show final state
    print("\n" + "-" * 60)
    print("FINAL STATE")
    print("-" * 60)
    demonstrate_get_user_plane_list(model)
    
    # Show the application
    app.Show()
    
    # Summary
    print("\n" + "=" * 60)
    print("DEMONSTRATION COMPLETE")
    print("=" * 60)
    print("""
User Plane services demonstrated (3 methods):

  - AddUserPlane: Create a new user-defined plane
  - GetUserPlaneList: List all user planes in the project
  - DeleteUserPlane: Remove a user plane from the project

PlaneEntityInfo Structure:
  - color: Display color for the plane
  - plane: Plane object containing:
      - id: Unique identifier/name for the plane
      - pole: Orientation as trend/plunge (pole to the plane)
      - quantity: Optional numeric value
      - weight: Optional weight value

Common Uses:
  - Pit wall orientations for slope stability analysis
  - Fault planes
  - Bedding planes
  - Reference planes for kinematic analysis
  - Custom analysis planes

Note: The pole represents the normal to the plane. For a plane 
dipping 45° to the south, the pole would be Trend=180°, Plunge=45°.
""")


if __name__ == "__main__":
    main()