Stereonet 2D Demo#

Comprehensive demonstration of Stereonet2D functionality in Dips Python API.

This script demonstrates Stereonet2D services including: - View Management: Create, Get, Close views - Entity Visibility: Poles, Intersections, Contours, Kinematic Analysis, Global Planes, Overlay - Entity Options: Pole options, Symbolic settings, Intersection options, Contour settings - Kinematic Analysis: Settings and visibility - Group Visibility: Sets, Planes, Traverses, Folds - Legend and Display Settings: Weighted, VectorMode, ProjectionMode - Entity References: Get and set individual entity visibility/options - Data Filters: Get and set active filter

Note: Tool demonstrations are in Stereonet2DToolsDemo.py

Code Snippet: Stereonet2DDemo.py#
"""
Comprehensive demonstration of Stereonet2D functionality in Dips Python API.

This script demonstrates Stereonet2D services including:
- View Management: Create, Get, Close views
- Entity Visibility: Poles, Intersections, Contours, Kinematic Analysis, Global Planes, Overlay
- Entity Options: Pole options, Symbolic settings, Intersection options, Contour settings
- Kinematic Analysis: Settings and visibility
- Group Visibility: Sets, Planes, Traverses, Folds
- Legend and Display Settings: Weighted, VectorMode, ProjectionMode
- Entity References: Get and set individual entity visibility/options
- Data Filters: Get and set active filter

Note: Tool demonstrations are in Stereonet2DToolsDemo.py
"""

import math
from dips import DipsApp
from dips import BuiltInDataFormatters
from dips import DipsAPI_pb2

# Helper value wrappers
import dips.TrendPlungeVal
import dips.AngleDataVal
import dips.ColorSurrogateVal

# Entity options and visibility wrappers
import dips.PoleEntityOptionsVal
import dips.IntersectionOptionsVal
import dips.ContourEntityVisibilityVal
import dips.ContourOptionsVal
import dips.GlobalPlaneEntityVisibilityVal
import dips.StereonetProjectionModeVal
import dips.StereonetOverlayEntityVisibilityVal
import dips.StereonetOverlaySettingsVal
import dips.SymbolicSettingsVal
import dips.VectorDensityContourSettingsVal
import dips.QuantitativeContourSettingsVal
import dips.KinematicAnalysisEntityVisibilityVal
import dips.KinematicAnalysisSettingsVal
import dips.SetVersusSetVal

# Data wrappers
import dips.DiscontinuityDataVal
import dips.OrientationDataSetVal


# =============================================================================
# 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


# =============================================================================
# SAMPLE DATA CREATION
# =============================================================================

def create_sample_traverse_with_poles(model):
    """Create a sample traverse with discontinuities (poles) for demonstration."""
    ods = model.GetDefaultOrientationDataSet()
    ods.name = "Sample Traverse for Stereonet2D Demo"
    ods.orientation_convention = DipsAPI_pb2.eOrientationConvention.TrendPlungeOrientation
    ods.orientation_data_type = DipsAPI_pb2.eOrientationDataType.SpotMapping
    ods.discontinuity_orientation_convention = DipsAPI_pb2.eOrientationConvention.TrendPlungeOrientation
    
    # Use built-in unit formatters
    ods.traverse_elevation_unit = BuiltInDataFormatters.LengthMeterDataFormatter
    ods.traverse_xyz_unit = BuiltInDataFormatters.LengthMeterDataFormatter
    ods.traverse_depth_unit = BuiltInDataFormatters.LengthMeterDataFormatter
    ods.survey_distance_unit = BuiltInDataFormatters.LengthMeterDataFormatter
    ods.discontinuity_distance_unit = BuiltInDataFormatters.LengthMeterDataFormatter
    ods.discontinuity_xyz_unit = BuiltInDataFormatters.LengthMeterDataFormatter
    ods.discontinuity_persistence_unit = BuiltInDataFormatters.LengthMeterDataFormatter
    
    # Create sample poles with different orientations
    sample_poles = [
        (45, 30), (90, 45), (135, 60), (180, 30),
        (225, 45), (270, 60), (315, 30), (0, 45),
        (60, 75), (120, 25), (240, 50), (300, 40),
    ]
    
    for trend_deg, plunge_deg in sample_poles:
        discontinuity = dips.DiscontinuityDataVal.DiscontinuityDataVal()
        discontinuity.orientation1.angle_radians = math.radians(trend_deg)
        discontinuity.orientation2.angle_radians = math.radians(plunge_deg)
        discontinuity.quantity = 1.0
        ods.discontinuity_list.append(discontinuity)
    
    return ods


# =============================================================================
# VIEW MANAGEMENT DEMONSTRATIONS
# =============================================================================

def demonstrate_view_management(model):
    """Demonstrate view creation and listing."""
    print("\n" + "=" * 60)
    print("VIEW MANAGEMENT")
    print("=" * 60)
    
    # Get existing views
    views = model.GetStereonet2DViewList()
    print(f"  Found {len(views)} existing Stereonet2D view(s)")
    
    # Create a new view
    print("  Creating new Stereonet2D view...")
    new_view = model.CreateStereonet2DView()
    view_value = new_view.GetValue()
    print(f"  ✓ Created view: '{view_value.view_name}'")
    
    return new_view


# =============================================================================
# ENTITY VISIBILITY DEMONSTRATIONS
# =============================================================================

def demonstrate_entity_visibility(view):
    """Demonstrate all entity visibility settings."""
    print("\n" + "=" * 60)
    print("ENTITY VISIBILITY")
    print("=" * 60)
    
    try:
        view.SetPoleEntityVisibility(True)
        print("  ✓ SetPoleEntityVisibility: True")
    except Exception as e:
        print(f"  ✗ SetPoleEntityVisibility: {e}")
    
    try:
        view.SetIntersectionEntityVisibility(True)
        print("  ✓ SetIntersectionEntityVisibility: True")
    except Exception as e:
        print(f"  ✗ SetIntersectionEntityVisibility: {e}")
    
    try:
        view.SetContourEntityVisibility(True)
        print("  ✓ SetContourEntityVisibility: True")
    except Exception as e:
        print(f"  ✗ SetContourEntityVisibility: {e}")
    
    try:
        view.SetKinematicAnalysisEntityVisibility(True)
        print("  ✓ SetKinematicAnalysisEntityVisibility: True")
    except Exception as e:
        print(f"  ✗ SetKinematicAnalysisEntityVisibility: {e}")
    
    try:
        view.SetGlobalMeanPlaneEntityVisibility(True)
        print("  ✓ SetGlobalMeanPlaneEntityVisibility: True")
    except Exception as e:
        print(f"  ✗ SetGlobalMeanPlaneEntityVisibility: {e}")
    
    try:
        view.SetGlobalBestFitPlaneEntityVisibility(True)
        print("  ✓ SetGlobalBestFitPlaneEntityVisibility: True")
    except Exception as e:
        print(f"  ✗ SetGlobalBestFitPlaneEntityVisibility: {e}")
    
    try:
        view.SetStereonetOverlayEntityVisibility(True)
        print("  ✓ SetStereonetOverlayEntityVisibility: True")
    except Exception as e:
        print(f"  ✗ SetStereonetOverlayEntityVisibility: {e}")


# =============================================================================
# ENTITY OPTIONS DEMONSTRATIONS
# =============================================================================

def demonstrate_pole_options(view, model):
    """Demonstrate pole entity options and symbolic settings."""
    print("\n" + "=" * 60)
    print("POLE OPTIONS")
    print("=" * 60)
    
    # Pole entity options
    try:
        pole_options = dips.PoleEntityOptionsVal.PoleEntityOptionsVal()
        pole_options.pole_mode = DipsAPI_pb2.ePoleMode.Vector
        pole_options.show_pole_planes = False
        pole_options.show_pole_vector_lines = True
        view.SetPoleEntityOptions(pole_options)
        print("  ✓ SetPoleEntityOptions (Vector mode)")
    except Exception as e:
        print(f"  ✗ SetPoleEntityOptions: {e}")
    
    # Symbolic settings
    try:
        symbolic = model.GetDefaultSymbolicSettings()
        view.SetSymbolicSettings(symbolic)
        print("  ✓ SetSymbolicSettings")
    except Exception as e:
        print(f"  ✗ SetSymbolicSettings: {e}")


def demonstrate_intersection_options(view, model):
    """Demonstrate intersection entity options."""
    print("\n" + "=" * 60)
    print("INTERSECTION OPTIONS")
    print("=" * 60)
    
    # Intersection entity options - use GetDefault
    try:
        intersection_options = model.GetDefaultIntersectionOptions()
        view.SetIntersectionEntityOptions(intersection_options)
        print("  ✓ SetIntersectionEntityOptions")
    except Exception as e:
        print(f"  ✗ SetIntersectionEntityOptions: {e}")
    
    # Intersection type
    try:
        view.SetIntersectionType(DipsAPI_pb2.eIntersectionType.AllPoleIntersections)
        print("  ✓ SetIntersectionType (AllPoleIntersections)")
    except Exception as e:
        print(f"  ✗ SetIntersectionType: {e}")
    
    # Set versus set (requires two sets to exist)
    try:
        sets = model.GetSetList()
        if len(sets) >= 2:
            set_vs_set = dips.SetVersusSetVal.SetVersusSetVal()
            set_vs_set.set_a = sets[0]
            set_vs_set.set_b = sets[1]
            view.SetSetVersusSet(set_vs_set)
            print("  ✓ SetSetVersusSet")
        else:
            print("  - SetSetVersusSet (needs 2+ sets)")
    except Exception as e:
        print(f"  ✗ SetSetVersusSet: {e}")


def demonstrate_contour_options(view, model):
    """Demonstrate contour entity options and settings."""
    print("\n" + "=" * 60)
    print("CONTOUR OPTIONS")
    print("=" * 60)
    
    # Contour entity options (no GetDefault available, use manual)
    try:
        contour_visibility = dips.ContourEntityVisibilityVal.ContourEntityVisibilityVal()
        contour_visibility.is_visible = True
        view.SetContourEntityOptions(contour_visibility)
        print("  ✓ SetContourEntityOptions")
    except Exception as e:
        print(f"  ✗ SetContourEntityOptions: {e}")
    
    # Contour type
    try:
        view.SetContourType(DipsAPI_pb2.eContourType.PoleVectorDensity)
        print("  ✓ SetContourType (PoleVectorDensity)")
    except Exception as e:
        print(f"  ✗ SetContourType: {e}")
    
    # Pole vector density contour settings - use GetDefault
    try:
        density_settings = model.GetDefaultVectorDensityContourSettings()
        view.SetPoleVectorDensityContourSettings(density_settings)
        print("  ✓ SetPoleVectorDensityContourSettings")
    except Exception as e:
        print(f"  ✗ SetPoleVectorDensityContourSettings: {e}")
    
    # Intersection vector density contour settings - use GetDefault
    try:
        density_settings = model.GetDefaultVectorDensityContourSettings()
        view.SetIntersectionVectorDensityContourSettings(density_settings)
        print("  ✓ SetIntersectionVectorDensityContourSettings")
    except Exception as e:
        print(f"  ✗ SetIntersectionVectorDensityContourSettings: {e}")
    
    # Quantitative contour settings - use GetDefault
    try:
        quant_settings = model.GetDefaultQuantitativeContourSettings()
        view.SetQuantitativeContourSettings(quant_settings)
        print("  ✓ SetQuantitativeContourSettings")
    except Exception as e:
        print(f"  ✗ SetQuantitativeContourSettings: {e}")
    
    # Contour options for each type - use GetDefault
    try:
        contour_options = model.GetDefaultContourOptions()
        view.SetPoleVectorContourOptions(contour_options)
        print("  ✓ SetPoleVectorContourOptions")
    except Exception as e:
        print(f"  ✗ SetPoleVectorContourOptions: {e}")
    
    try:
        contour_options = model.GetDefaultContourOptions()
        view.SetIntersectionVectorContourOptions(contour_options)
        print("  ✓ SetIntersectionVectorContourOptions")
    except Exception as e:
        print(f"  ✗ SetIntersectionVectorContourOptions: {e}")
    
    try:
        contour_options = model.GetDefaultContourOptions()
        view.SetQuantitativeContourOptions(contour_options)
        print("  ✓ SetQuantitativeContourOptions")
    except Exception as e:
        print(f"  ✗ SetQuantitativeContourOptions: {e}")


def demonstrate_kinematic_analysis(view, model):
    """Demonstrate kinematic analysis options and settings."""
    print("\n" + "=" * 60)
    print("KINEMATIC ANALYSIS")
    print("=" * 60)
    
    # Kinematic analysis entity options (no GetDefault available, use manual)
    try:
        kinematic_visibility = dips.KinematicAnalysisEntityVisibilityVal.KinematicAnalysisEntityVisibilityVal()
        kinematic_visibility.is_visible = True
        view.SetKinematicAnalysisEntityOptions(kinematic_visibility)
        print("  ✓ SetKinematicAnalysisEntityOptions")
    except Exception as e:
        print(f"  ✗ SetKinematicAnalysisEntityOptions: {e}")
    
    # Kinematic analysis settings - use GetDefault and modify
    try:
        kinematic_settings = model.GetDefaultKinematicAnalysisSettings()
        kinematic_settings.failure_mode_option = DipsAPI_pb2.eFailureModeOption.PlanarSliding
        kinematic_settings.slope_dip.angle_radians = math.radians(45)
        kinematic_settings.slope_dip_direction.angle_radians = math.radians(180)
        kinematic_settings.friction_angle.angle_radians = math.radians(30)
        view.SetKinematicAnalysisSettings(kinematic_settings)
        print("  ✓ SetKinematicAnalysisSettings (Planar Sliding)")
    except Exception as e:
        print(f"  ✗ SetKinematicAnalysisSettings: {e}")


def demonstrate_global_plane_options(view):
    """Demonstrate global plane options."""
    print("\n" + "=" * 60)
    print("GLOBAL PLANE OPTIONS")
    print("=" * 60)
    
    # Global mean plane
    try:
        global_mean = dips.GlobalPlaneEntityVisibilityVal.GlobalPlaneEntityVisibilityVal()
        global_mean.is_visible = True
        view.SetGlobalMeanPlaneEntityOptions(global_mean)
        print("  ✓ SetGlobalMeanPlaneEntityOptions")
    except Exception as e:
        print(f"  ✗ SetGlobalMeanPlaneEntityOptions: {e}")
    
    # Global best fit plane
    try:
        global_best_fit = dips.GlobalPlaneEntityVisibilityVal.GlobalPlaneEntityVisibilityVal()
        global_best_fit.is_visible = True
        view.SetGlobalBestFitPlaneEntityOptions(global_best_fit)
        print("  ✓ SetGlobalBestFitPlaneEntityOptions")
    except Exception as e:
        print(f"  ✗ SetGlobalBestFitPlaneEntityOptions: {e}")


def demonstrate_stereonet_overlay(view):
    """Demonstrate stereonet overlay options."""
    print("\n" + "=" * 60)
    print("STEREONET OVERLAY")
    print("=" * 60)
    
    # Polar overlay
    try:
        overlay_visibility = dips.StereonetOverlayEntityVisibilityVal.StereonetOverlayEntityVisibilityVal()
        overlay_visibility.is_visible = True
        overlay_settings = dips.StereonetOverlaySettingsVal.StereonetOverlaySettingsVal()
        overlay_settings.option = DipsAPI_pb2.eStereonetOverlayOption.Polar
        overlay_settings.color = create_color(128, 128, 128, 180)
        overlay_visibility.stereonet_overlay_settings = overlay_settings
        view.SetStereonetOverlayEntityOptions(overlay_visibility)
        print("  ✓ SetStereonetOverlayEntityOptions (Polar)")
    except Exception as e:
        print(f"  ✗ SetStereonetOverlayEntityOptions (Polar): {e}")
    
    # Equatorial overlay
    try:
        overlay_visibility = dips.StereonetOverlayEntityVisibilityVal.StereonetOverlayEntityVisibilityVal()
        overlay_visibility.is_visible = True
        overlay_settings = dips.StereonetOverlaySettingsVal.StereonetOverlaySettingsVal()
        overlay_settings.option = DipsAPI_pb2.eStereonetOverlayOption.Equatorial
        overlay_settings.color = create_color(0, 0, 255, 180)
        overlay_visibility.stereonet_overlay_settings = overlay_settings
        view.SetStereonetOverlayEntityOptions(overlay_visibility)
        print("  ✓ SetStereonetOverlayEntityOptions (Equatorial)")
    except Exception as e:
        print(f"  ✗ SetStereonetOverlayEntityOptions (Equatorial): {e}")
    
    # Custom overlay
    try:
        overlay_visibility = dips.StereonetOverlayEntityVisibilityVal.StereonetOverlayEntityVisibilityVal()
        overlay_visibility.is_visible = True
        overlay_settings = dips.StereonetOverlaySettingsVal.StereonetOverlaySettingsVal()
        overlay_settings.option = DipsAPI_pb2.eStereonetOverlayOption.CustomOverlay
        overlay_settings.color = create_color(255, 0, 0, 180)
        overlay_settings.custom_orientation = create_trend_plunge(45, 60)
        overlay_visibility.stereonet_overlay_settings = overlay_settings
        view.SetStereonetOverlayEntityOptions(overlay_visibility)
        print("  ✓ SetStereonetOverlayEntityOptions (Custom)")
    except Exception as e:
        print(f"  ✗ SetStereonetOverlayEntityOptions (Custom): {e}")


# =============================================================================
# GROUP VISIBILITY DEMONSTRATIONS
# =============================================================================

def demonstrate_group_visibility(view):
    """Demonstrate all group visibility settings."""
    print("\n" + "=" * 60)
    print("GROUP VISIBILITY")
    print("=" * 60)
    
    try:
        view.SetSetWindowEntityGroupVisibility(True)
        print("  ✓ SetSetWindowEntityGroupVisibility: True")
    except Exception as e:
        print(f"  ✗ SetSetWindowEntityGroupVisibility: {e}")
    
    try:
        view.SetMeanSetPlaneEntityGroupVisibility(True)
        print("  ✓ SetMeanSetPlaneEntityGroupVisibility: True")
    except Exception as e:
        print(f"  ✗ SetMeanSetPlaneEntityGroupVisibility: {e}")
    
    try:
        view.SetUserPlaneEntityGroupVisibility(True)
        print("  ✓ SetUserPlaneEntityGroupVisibility: True")
    except Exception as e:
        print(f"  ✗ SetUserPlaneEntityGroupVisibility: {e}")
    
    try:
        view.SetTraverseEntityGroupVisibility(True)
        print("  ✓ SetTraverseEntityGroupVisibility: True")
    except Exception as e:
        print(f"  ✗ SetTraverseEntityGroupVisibility: {e}")
    
    try:
        view.SetFoldWindowEntityGroupVisibility(True)
        print("  ✓ SetFoldWindowEntityGroupVisibility: True")
    except Exception as e:
        print(f"  ✗ SetFoldWindowEntityGroupVisibility: {e}")
    
    try:
        view.SetBestFitFoldPlaneEntityGroupVisibility(True)
        print("  ✓ SetBestFitFoldPlaneEntityGroupVisibility: True")
    except Exception as e:
        print(f"  ✗ SetBestFitFoldPlaneEntityGroupVisibility: {e}")


# =============================================================================
# LEGEND AND DISPLAY SETTINGS
# =============================================================================

def demonstrate_legend_and_settings(view, model):
    """Demonstrate legend and display settings."""
    print("\n" + "=" * 60)
    print("LEGEND AND DISPLAY SETTINGS")
    print("=" * 60)
    
    # Legend visibility
    try:
        view.SetLegendVisibility(True)
        print("  ✓ SetLegendVisibility: True")
    except Exception as e:
        print(f"  ✗ SetLegendVisibility: {e}")
    
    # IsWeighted
    try:
        view.SetIsWeighted(False)
        print("  ✓ SetIsWeighted: False")
    except Exception as e:
        print(f"  ✗ SetIsWeighted: {e}")
    
    # VectorMode
    try:
        view.SetVectorMode(DipsAPI_pb2.eVectorMode.Pole)
        print("  ✓ SetVectorMode: Pole")
    except Exception as e:
        print(f"  ✗ SetVectorMode: {e}")
    
    # ProjectionMode - use GetDefault and modify
    try:
        projection = model.GetDefaultStereonetProjectionMode()
        projection.hemisphere_draw_option = DipsAPI_pb2.eHemisphereDrawOption.Lower
        projection.projection_method_draw_option = DipsAPI_pb2.eProjectionMethodDrawOption.EqualArea
        view.SetProjectionMode(projection)
        print("  ✓ SetProjectionMode: Lower Hemisphere, EqualArea")
    except Exception as e:
        print(f"  ✗ SetProjectionMode: {e}")


# =============================================================================
# ENTITY REFERENCE DEMONSTRATIONS
# =============================================================================

def demonstrate_entity_references(view):
    """Demonstrate getting and setting entity references."""
    print("\n" + "=" * 60)
    print("ENTITY REFERENCES")
    print("=" * 60)
    
    try:
        entities = view.GetSetWindowEntityVisibilityList()
        print(f"  ✓ GetSetWindowEntityVisibilityList: {len(entities)} found")
    except Exception as e:
        print(f"  ✗ GetSetWindowEntityVisibilityList: {e}")
    
    try:
        entities = view.GetMeanSetPlaneEntityVisibilityList()
        print(f"  ✓ GetMeanSetPlaneEntityVisibilityList: {len(entities)} found")
    except Exception as e:
        print(f"  ✗ GetMeanSetPlaneEntityVisibilityList: {e}")
    
    try:
        entities = view.GetUserPlaneEntityVisibilityList()
        print(f"  ✓ GetUserPlaneEntityVisibilityList: {len(entities)} found")
    except Exception as e:
        print(f"  ✗ GetUserPlaneEntityVisibilityList: {e}")
    
    try:
        entities = view.GetTraverseEntityVisibilityList()
        print(f"  ✓ GetTraverseEntityVisibilityList: {len(entities)} found")
    except Exception as e:
        print(f"  ✗ GetTraverseEntityVisibilityList: {e}")
    
    try:
        entities = view.GetFoldWindowEntityVisibilityList()
        print(f"  ✓ GetFoldWindowEntityVisibilityList: {len(entities)} found")
    except Exception as e:
        print(f"  ✗ GetFoldWindowEntityVisibilityList: {e}")
    
    try:
        entities = view.GetBestFitFoldPlaneEntityVisibilityList()
        print(f"  ✓ GetBestFitFoldPlaneEntityVisibilityList: {len(entities)} found")
    except Exception as e:
        print(f"  ✗ GetBestFitFoldPlaneEntityVisibilityList: {e}")


def demonstrate_individual_entity_visibility(view):
    """Demonstrate setting visibility and options for individual entities."""
    print("\n" + "=" * 60)
    print("INDIVIDUAL ENTITY VISIBILITY/OPTIONS")
    print("=" * 60)
    
    # Set Window entities
    try:
        entities = view.GetSetWindowEntityVisibilityList()
        if entities:
            entities[0].SetSetWindowEntityVisibility(True)
            print(f"  ✓ SetSetWindowEntityVisibility: True")
        else:
            print("  - SetSetWindowEntityVisibility: No set windows available")
    except Exception as e:
        print(f"  ✗ SetSetWindowEntityVisibility: {e}")
    
    # Mean Set Plane entities
    try:
        entities = view.GetMeanSetPlaneEntityVisibilityList()
        if entities:
            entities[0].SetMeanSetPlaneEntityVisibility(True)
            print(f"  ✓ SetMeanSetPlaneEntityVisibility: True")
            # Also demonstrate SetMeanSetPlaneEntityOptions
            try:
                import dips.SetEntityOptionsVal
                opts = dips.SetEntityOptionsVal.SetEntityOptionsVal()
                opts.show_label = True
                entities[0].SetMeanSetPlaneEntityOptions(opts)
                print(f"  ✓ SetMeanSetPlaneEntityOptions")
            except Exception as e:
                print(f"  ✗ SetMeanSetPlaneEntityOptions: {e}")
        else:
            print("  - SetMeanSetPlaneEntityVisibility: No mean set planes available")
    except Exception as e:
        print(f"  ✗ SetMeanSetPlaneEntityVisibility: {e}")
    
    # User Plane entities
    try:
        entities = view.GetUserPlaneEntityVisibilityList()
        if entities:
            entities[0].SetUserPlaneEntityVisibility(True)
            print(f"  ✓ SetUserPlaneEntityVisibility: True")
            # Also demonstrate SetUserPlaneEntityOptions
            try:
                import dips.UserPlaneEntityOptionsVal
                opts = dips.UserPlaneEntityOptionsVal.UserPlaneEntityOptionsVal()
                opts.show_label = True
                entities[0].SetUserPlaneEntityOptions(opts)
                print(f"  ✓ SetUserPlaneEntityOptions")
            except Exception as e:
                print(f"  ✗ SetUserPlaneEntityOptions: {e}")
        else:
            print("  - SetUserPlaneEntityVisibility: No user planes available")
    except Exception as e:
        print(f"  ✗ SetUserPlaneEntityVisibility: {e}")
    
    # Traverse entities
    try:
        entities = view.GetTraverseEntityVisibilityList()
        if entities:
            entities[0].SetTraverseEntityVisibility(True)
            print(f"  ✓ SetTraverseEntityVisibility: True")
            # Also demonstrate SetTraverseEntityOptions
            try:
                import dips.TraverseEntityOptionsVal
                opts = dips.TraverseEntityOptionsVal.TraverseEntityOptionsVal()
                opts.show_label = True
                entities[0].SetTraverseEntityOptions(opts)
                print(f"  ✓ SetTraverseEntityOptions")
            except Exception as e:
                print(f"  ✗ SetTraverseEntityOptions: {e}")
        else:
            print("  - SetTraverseEntityVisibility: No traverses available")
    except Exception as e:
        print(f"  ✗ SetTraverseEntityVisibility: {e}")
    
    # Fold Window entities
    try:
        entities = view.GetFoldWindowEntityVisibilityList()
        if entities:
            entities[0].SetFoldWindowEntityVisibility(True)
            print(f"  ✓ SetFoldWindowEntityVisibility: True")
        else:
            print("  - SetFoldWindowEntityVisibility: No fold windows available")
    except Exception as e:
        print(f"  ✗ SetFoldWindowEntityVisibility: {e}")
    
    # Fold entities (best fit fold planes)
    try:
        entities = view.GetBestFitFoldPlaneEntityVisibilityList()
        if entities:
            entities[0].SetFoldEntityVisibility(True)
            print(f"  ✓ SetFoldEntityVisibility: True")
            # Also demonstrate SetFoldEntityOptions
            try:
                import dips.FoldEntityOptionsVal
                opts = dips.FoldEntityOptionsVal.FoldEntityOptionsVal()
                opts.show_label = True
                entities[0].SetFoldEntityOptions(opts)
                print(f"  ✓ SetFoldEntityOptions")
            except Exception as e:
                print(f"  ✗ SetFoldEntityOptions: {e}")
        else:
            print("  - SetFoldEntityVisibility: No fold entities available")
    except Exception as e:
        print(f"  ✗ SetFoldEntityVisibility: {e}")


# =============================================================================
# DATA FILTER DEMONSTRATIONS
# =============================================================================

def demonstrate_active_data_filter(view, model):
    """Demonstrate active data filter management."""
    print("\n" + "=" * 60)
    print("ACTIVE DATA FILTER")
    print("=" * 60)
    
    # Get current active filter
    try:
        active_filter = view.GetActiveDataFilter()
        if active_filter:
            filter_value = active_filter.GetValue()
            print(f"  ✓ GetActiveDataFilter: '{filter_value.name}'")
        else:
            print("  ✓ GetActiveDataFilter: None (no active filter)")
    except Exception as e:
        print(f"  ✗ GetActiveDataFilter: {e}")
    
    # Set active filter (if filters exist)
    try:
        filters = model.GetDataFilterList()
        if filters:
            view.SetActiveDataFilter(filters[0])
            filter_value = filters[0].GetValue()
            print(f"  ✓ SetActiveDataFilter: '{filter_value.name}'")
        else:
            print("  - SetActiveDataFilter: No filters available")
    except Exception as e:
        print(f"  ✗ SetActiveDataFilter: {e}")


# =============================================================================
# VIEW CLOSE DEMONSTRATION
# =============================================================================

def demonstrate_close_view(view):
    """Demonstrate closing a view."""
    print("\n" + "=" * 60)
    print("CLOSE VIEW")
    print("=" * 60)
    
    try:
        view_value = view.GetValue()
        view_name = view_value.view_name
        view.CloseStereonet2DView()
        print(f"  ✓ CloseStereonet2DView: '{view_name}'")
    except Exception as e:
        print(f"  ✗ CloseStereonet2DView: {e}")


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

def main():
    """Main demonstration function."""
    print("=" * 60)
    print("Dips API - Stereonet2D Comprehensive 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()
    
    # Create sample data if needed
    print("\n" + "-" * 60)
    print("SAMPLE DATA SETUP")
    print("-" * 60)
    try:
        traverses = model.GetTraverseList()
        if len(traverses) == 0:
            print("Creating sample traverse with poles...")
            ods = create_sample_traverse_with_poles(model)
            model.AddTraverse(ods)
            print(f"  ✓ Created traverse with {len(ods.discontinuity_list)} poles")
        else:
            print(f"  ✓ Found {len(traverses)} existing traverse(s)")
    except Exception as e:
        print(f"  Note: {e}")
    
    # Get or create a view
    views = model.GetStereonet2DViewList()
    if views:
        view = views[0]
        print(f"  Using existing view: '{view.GetValue().view_name}'")
    else:
        view = demonstrate_view_management(model)
    
    # Run all demonstrations
    demonstrate_entity_visibility(view)
    demonstrate_pole_options(view, model)
    demonstrate_intersection_options(view, model)
    demonstrate_contour_options(view, model)
    demonstrate_kinematic_analysis(view, model)
    demonstrate_global_plane_options(view)
    demonstrate_stereonet_overlay(view)
    demonstrate_group_visibility(view)
    demonstrate_legend_and_settings(view, model)
    demonstrate_entity_references(view)
    demonstrate_individual_entity_visibility(view)
    demonstrate_active_data_filter(view, model)
    
    # Create and close a new view to demonstrate view lifecycle
    print("\n" + "-" * 60)
    print("VIEW LIFECYCLE DEMO")
    print("-" * 60)
    new_view = model.CreateStereonet2DView()
    print(f"  ✓ Created new view: '{new_view.GetValue().view_name}'")
    demonstrate_close_view(new_view)
    
    # Show the application
    print("\n" + "-" * 60)
    app.Show()
    
    # Summary
    print("\n" + "=" * 60)
    print("DEMONSTRATION COMPLETE")
    print("=" * 60)
    print("""
Stereonet2D services demonstrated (56 methods):

VIEW MANAGEMENT (3 methods):
  - GetStereonet2DViewList
  - CreateStereonet2DView
  - CloseStereonet2DView

ENTITY VISIBILITY (7 methods):
  - SetPoleEntityVisibility
  - SetIntersectionEntityVisibility
  - SetContourEntityVisibility
  - SetKinematicAnalysisEntityVisibility
  - SetGlobalMeanPlaneEntityVisibility
  - SetGlobalBestFitPlaneEntityVisibility
  - SetStereonetOverlayEntityVisibility

ENTITY OPTIONS (18 methods):
  - SetPoleEntityOptions
  - SetSymbolicSettings
  - SetIntersectionEntityOptions
  - SetIntersectionType
  - SetSetVersusSet
  - SetContourEntityOptions
  - SetContourType
  - SetPoleVectorDensityContourSettings
  - SetIntersectionVectorDensityContourSettings
  - SetQuantitativeContourSettings
  - SetPoleVectorContourOptions
  - SetIntersectionVectorContourOptions
  - SetQuantitativeContourOptions
  - SetKinematicAnalysisEntityOptions
  - SetKinematicAnalysisSettings
  - SetGlobalMeanPlaneEntityOptions
  - SetGlobalBestFitPlaneEntityOptions
  - SetStereonetOverlayEntityOptions

GROUP VISIBILITY (6 methods):
  - SetSetWindowEntityGroupVisibility
  - SetMeanSetPlaneEntityGroupVisibility
  - SetUserPlaneEntityGroupVisibility
  - SetTraverseEntityGroupVisibility
  - SetFoldWindowEntityGroupVisibility
  - SetBestFitFoldPlaneEntityGroupVisibility

LEGEND AND SETTINGS (4 methods):
  - SetLegendVisibility
  - SetIsWeighted
  - SetVectorMode
  - SetProjectionMode

ENTITY REFERENCE LISTS (6 methods):
  - GetSetWindowEntityVisibilityList
  - GetMeanSetPlaneEntityVisibilityList
  - GetUserPlaneEntityVisibilityList
  - GetTraverseEntityVisibilityList
  - GetFoldWindowEntityVisibilityList
  - GetBestFitFoldPlaneEntityVisibilityList

INDIVIDUAL ENTITY VISIBILITY/OPTIONS (10 methods):
  - SetSetWindowEntityVisibility
  - SetMeanSetPlaneEntityVisibility
  - SetMeanSetPlaneEntityOptions
  - SetUserPlaneEntityVisibility
  - SetUserPlaneEntityOptions
  - SetTraverseEntityVisibility
  - SetTraverseEntityOptions
  - SetFoldWindowEntityVisibility
  - SetFoldEntityVisibility
  - SetFoldEntityOptions

DATA FILTER (2 methods):
  - GetActiveDataFilter
  - SetActiveDataFilter
""")


if __name__ == "__main__":
    main()