Skip to main content

Analysis Operations

Object Operations 📥 Download Script

Analysis Operations Tutorial.

This tutorial demonstrates complete workflows for various types of 3D analyses, including wall thickness, deviation, curvature, extrema, gray value, and void/inclusion. Each section covers the full lifecycle from creation to export.

Note: The UI analysis tools are heavily based on user interaction, such as picking points on the target object to find values, viewing frequency vs. statistics distribution charts, etc. Since user interactions cannot be performed through the scripting interface, the scripting analysis operations have certain limitations. For interactive analysis, it is highly recommended to use the UI tools located under the Analyze ribbon tab. The UI tools also provide options to generate detailed 3D PDF reports, including snapshots, measurements, interactive 3D scenes, charts, and more.

Prerequisites
  • Volvicon application must be running
  • Relevant objects loaded (volumes, masks, and surfaces as required)

Creating Analyses​

# # Wall thickness (mask)
# wall_thickness_params = api.WallThicknessParams()
# wall_thickness_params.mask_preview_surface_quality = api.Mask3dPreviewQuality.High
# # ShrinkingSphere uses search_angle to select an opposing surface contact.
# wall_thickness_params.method = api.WallThicknessMethod.ShrinkingSphere
# wall_thickness_params.max_wall_thickness = 10000
# # Use the smallest angle that reliably reaches the intended wall.
# wall_thickness_params.search_angle = 20
# wt_name = analysis_operations.create_wall_thickness_analysis_mask(
# "WallThickness_Mask_1",
# active_mask_name, # mask_name (string)
# wall_thickness_params
# )

# # Wall thickness (surface)
# wall_thickness_params_surface = api.WallThicknessParams()
# wall_thickness_params_surface.mask_preview_surface_quality = api.Mask3dPreviewQuality.High
# # RayCasting is generally preferable when normal-direction hits are suitable.
# wall_thickness_params_surface.method = api.WallThicknessMethod.RayCasting
# wall_thickness_params_surface.max_wall_thickness = 10000
# # search_angle is ignored by RayCasting.
# wall_thickness_params_surface.search_angle = 20
# wt_surf_name = analysis_operations.create_wall_thickness_analysis_surface(
# "WallThickness_Surface_1",
# active_surface_name, # surface_name (string)
# wall_thickness_params_surface
# )

# # Deviation (mask vs mask / surface vs surface / mask vs surface)
# deviation_params_signed = api.DeviationParams()
# deviation_params_signed.method = api.DeviationMethod.Signed
# dev_mvm_name = analysis_operations.create_deviation_analysis_mask_vs_mask(
# "Deviation_MvM",
# active_mask_name,
# app.get_all_mask_names()[0],
# deviation_params_signed
# )
#
# deviation_params_unsigned = api.DeviationParams()
# deviation_params_unsigned.method = api.DeviationMethod.Unsigned
# dev_svs_name = analysis_operations.create_deviation_analysis_surface_vs_surface(
# "Deviation_SvS",
# active_surface_name,
# app.get_all_surface_names()[0],
# deviation_params_unsigned
# )
#
# deviation_params_default = api.DeviationParams()
# dev_mvs_name = analysis_operations.create_deviation_analysis_mask_vs_surface(
# "Deviation_MvS",
# active_mask_name,
# active_surface_name,
# deviation_params_default
# )

# # Curvature (mask / surface)
# curvature_params_mask = api.CurvatureParams()
# curvature_params_mask.method = api.CurvatureMethod.Gaussian
# curv_mask = analysis_operations.create_curvature_analysis_mask(
# "Curvature_Mask",
# active_mask_name,
# curvature_params_mask
# )
#
# curvature_params_surface = api.CurvatureParams()
# curvature_params_surface.method = api.CurvatureMethod.Mean
# curv_surface = analysis_operations.create_curvature_analysis_surface(
# "Curvature_Surface",
# active_surface_name,
# curvature_params_surface
# )

# # Extrema (mask / surface)
# extrema_params_mask = api.ExtremaParams()
# extrema_params_mask.method = api.ExtremaMethod.MaximumAndMinimum
# extrema_params_mask.axis = [0.0, 0.0, 1.0]
# ext_mask = analysis_operations.create_extrema_analysis_mask(
# "Extrema_Mask",
# active_mask_name,
# extrema_params_mask
# )
#
# extrema_params_surface = api.ExtremaParams()
# extrema_params_surface.method = api.ExtremaMethod.Maximum
# ext_surface = analysis_operations.create_extrema_analysis_surface(
# "Extrema_Surface",
# active_surface_name,
# extrema_params_surface
# )

# # Gray value (mask / surface)
# gray_value_params_mask = api.GrayValueParams()
# gray_value_params_mask.mask_preview_surface_quality = api.Mask3dPreviewQuality.Optimal
# gv_mask = analysis_operations.create_gray_value_analysis_mask(
# "GrayValue_Mask",
# active_mask_name,
# active_volume_name,
# gray_value_params_mask
# )
#
# gray_value_params_surface = api.GrayValueParams()
# gray_value_params_surface.mask_preview_surface_quality = api.Mask3dPreviewQuality.Optimal
# gv_surface = analysis_operations.create_gray_value_analysis_surface(
# "GrayValue_Surface",
# active_surface_name,
# active_volume_name,
# gray_value_params_surface
# )

# # Void / inclusion
# void_inclusion_params = api.VoidInclusionParams()
# void_inclusion_params.mode = api.VoidInclusionTargetType.Void
# void_inclusion_params.method = api.VoidInclusionMethod.Absolute
# void_inclusion_params.auto_absolute_contrast = True
# void_inclusion_params.auto_air_gray_value = True
# void_inclusion_params.requested_statistics = [
# "Volume (mm³)",
# "Volume fraction (%)",
# "Centroid X (mm)",
# "Centroid Y (mm)",
# "Centroid Z (mm)",
# "Compactness",
# "Sphericity",
# "Equivalent diameter (mm)"
# ]
# void_inclusion_filtering_params = api.VoidInclusionFilteringParams()
# void_inclusion_filtering_params.enable_geometric_filtering = True
# void_inclusion_filtering_params.probability_threshold = 0.0
# void_inclusion_filtering_params.min_voxel_count = 8
# void_inclusion_filtering_params.max_voxel_count = 10000000
# void_inclusion_filtering_params.min_compactness = 0.0
# void_inclusion_filtering_params.max_compactness = 1.0
# void_inclusion_filtering_params.min_sphericity = 0.0
# void_inclusion_filtering_params.max_sphericity = 1.0
# void_inclusion_filtering_params.min_volume_fraction_percent = 0.0
# void_inclusion_filtering_params.max_volume_fraction_percent = 100.0
# void_inclusion_filtering_params.min_equivalent_diameter = 0.0
# void_inclusion_filtering_params.max_equivalent_diameter = 1000000.0
# void_inclusion_filtering_params.max_count = 10000
# void_inclusion_params.filter_result_params = void_inclusion_filtering_params
# vi_name = analysis_operations.create_void_inclusion_analysis(
# "VoidInclusion_1",
# active_volume_name,
# "", # roi_mask_name (string, empty to disable)
# void_inclusion_params
# )

# all_analyses = app.get_all_analysis_names()
# print(f"Available analyses: {all_analyses}")

1. Wall Thickness Analysis Workflow​

# # A. Creation
# wall_thickness_params = api.WallThicknessParams()
# wall_thickness_params.mask_preview_surface_quality = api.Mask3dPreviewQuality.High
# # ShrinkingSphere selects the opposing contact; it does not report sphere diameter.
# wall_thickness_params.method = api.WallThicknessMethod.ShrinkingSphere
# wall_thickness_params.max_wall_thickness = 10.0
# wall_thickness_params.search_angle = 20.0
# wt_name = analysis_operations.create_wall_thickness_analysis_mask(
# "WallThickness_Mask_1",
# active_mask_name,
# wall_thickness_params
# )
#
# # B. Running
# analysis_operations.run_analysis(wt_name)
#
# # C. Getting Info and Results
# analysis_info : api.AnalysisInfo = analysis_operations.get_analysis_info(wt_name)
# print(f"Analysis info: name={analysis_info.name}, type={analysis_info.type}")
#
# # Get specific analysis type name
# analysis_type_str = analysis_operations.get_analysis_type_as_string(wt_name)
# print(f"Analysis type name: {analysis_type_str}")
#
# # Check if analysis has results
# has_results = analysis_operations.has_analysis_results(wt_name)
# print(f"Has results: {has_results}")
#
# wall_thickness_analysis_results : api.WallThicknessAnalysisResults = analysis_operations.get_wall_thickness_analysis_results(wt_name)
# wall_thickness_statistics : api.WallThicknessAnalysisStatistics = wall_thickness_analysis_results.statistics
# print(f"Wall Thickness Mean: {wall_thickness_statistics.mean_value}")
# for sample in wall_thickness_analysis_results.samples[:3]:
# wall_thickness_sample : api.WallThicknessSample = sample
# # For a valid sample, value is the distance between the surface contacts.
# print(
# f"Sample thickness: value={wall_thickness_sample.value}, "
# f"point_a={wall_thickness_sample.point_a}, point_b={wall_thickness_sample.point_b}"
# )
#
# # D. Writing Results to Disk
# # The file classifies values outside the result range as -inf or +inf; returned samples remain numeric.
# analysis_operations.write_wall_thickness_results_to_disk(wall_thickness_analysis_results, r'C:\output\wall_thickness.txt')
#
# # E. Changing Display Settings
# analysis_display_settings = api.AnalysisDisplaySettings()
# analysis_display_settings.above_max_range_color = [1.0, 0.6, 0.6]
# analysis_display_settings.lookup_table_type = api.LookupTableType.ReverseRainbow
# analysis_display_settings.below_min_range_color = [0.6, 0.0, 1.0]
# analysis_display_settings.constant_color = [0.0, 0.0, 1.0]
# analysis_display_settings.lookup_table_opacity = 1.0
# analysis_display_settings.range = [0.0, 5.0]
# analysis_operations.set_display_settings(wt_name, analysis_display_settings)
# current_settings : api.AnalysisDisplaySettings = analysis_operations.get_display_settings(wt_name)
#
# # Restoring visualization defaults
# # analysis_operations.restore_visualizations(wt_name)
#
# # F. Updating Analysis
# # analysis_operations.update_analysis(wt_name)

2. Deviation Analysis Workflow​

# # A. Creation (Mask vs Mask)
# deviation_params = api.DeviationParams()
# deviation_params.method = api.DeviationMethod.Signed
# dev_name = analysis_operations.create_deviation_analysis_mask_vs_mask(
# "Deviation_MvM_1",
# active_mask_name,
# app.get_all_mask_names()[0],
# deviation_params
# )
#
# # B. Running
# analysis_operations.run_analysis(dev_name)
#
# # C. Getting Info and Results
# analysis_info : api.AnalysisInfo = analysis_operations.get_analysis_info(dev_name)
# print(f"Analysis info: name={analysis_info.name}, type={analysis_info.type}")
#
# deviation_analysis_results : api.DeviationAnalysisResults = analysis_operations.get_deviation_analysis_results(dev_name)
# deviation_statistics : api.DeviationAnalysisStatistics = deviation_analysis_results.statistics
# print(f"Deviation Mean: {deviation_statistics.mean_value}")
# for sample in deviation_analysis_results.samples[:3]:
# deviation_sample : api.DeviationSample = sample
# print(f"Deviation sample: {deviation_sample.value}")
#
# # D. Writing Results to Disk
# # The file classifies values outside the result range as -inf or +inf; returned samples remain numeric.
# analysis_operations.write_deviation_results_to_disk(deviation_analysis_results, r'C:\output\deviation.txt')
#
# # E. Changing Display Settings
# display = api.AnalysisDisplaySettings()
# display.lookup_table_type = api.LookupTableType.ReverseRainbow
# display.range = [-1.0, 1.0]
# analysis_operations.set_display_settings(dev_name, display)
#
# # F. Updating Analysis
# # analysis_operations.update_analysis(dev_name)

3. Curvature Analysis Workflow​

# # A. Creation
# curvature_params = api.CurvatureParams()
# curvature_params.method = api.CurvatureMethod.Gaussian
# curv_name = analysis_operations.create_curvature_analysis_mask(
# "Curvature_Mask_1",
# active_mask_name,
# curvature_params
# )
#
# # B. Running
# analysis_operations.run_analysis(curv_name)
#
# # C. Getting Info and Results
# analysis_info : api.AnalysisInfo = analysis_operations.get_analysis_info(curv_name)
# print(f"Analysis info: name={analysis_info.name}, type={analysis_info.type}")
#
# curvature_analysis_results : api.CurvatureAnalysisResults = analysis_operations.get_curvature_analysis_results(curv_name)
# curvature_statistics : api.CurvatureAnalysisStatistics = curvature_analysis_results.statistics
# print(f"Curvature Mean: {curvature_statistics.mean_value}")
# for sample in curvature_analysis_results.samples[:3]:
# curvature_sample : api.CurvatureSample = sample
# print(f"Curvature sample: {curvature_sample.value}")
#
# # D. Writing Results to Disk
# # The file classifies values outside the result range as -inf or +inf; returned samples remain numeric.
# analysis_operations.write_curvature_results_to_disk(curvature_analysis_results, r'C:\output\curvature.txt')
#
# # E. Changing Display Settings
# display = api.AnalysisDisplaySettings()
# display.lookup_table_type = api.LookupTableType.ReverseRainbow
# analysis_operations.set_display_settings(curv_name, display)
#
# # F. Updating Analysis
# # analysis_operations.update_analysis(curv_name)

4. Extrema Analysis Workflow​

# # A. Creation
# extrema_params = api.ExtremaParams()
# extrema_params.method = api.ExtremaMethod.MaximumAndMinimum
# extrema_params.axis = [0.0, 0.0, 1.0]
# ext_name = analysis_operations.create_extrema_analysis_mask(
# "Extrema_Mask_1",
# active_mask_name,
# extrema_params
# )
#
# # B. Running
# analysis_operations.run_analysis(ext_name)
#
# # C. Getting Info and Results
# analysis_info : api.AnalysisInfo = analysis_operations.get_analysis_info(ext_name)
# print(f"Analysis info: name={analysis_info.name}, type={analysis_info.type}")
#
# extrema_analysis_results : api.ExtremaAnalysisResults = analysis_operations.get_extrema_analysis_results(ext_name)
# extrema_statistics : api.ExtremaAnalysisStatistics = extrema_analysis_results.statistics
# print(f"Extrema Max: {extrema_statistics.max_value}")
# for sample in extrema_analysis_results.samples[:3]:
# extrema_sample : api.ExtremaSample = sample
# print(f"Extrema sample: {extrema_sample.value}")
#
# # D. Writing Results to Disk
# # The file classifies values outside the result range as -inf or +inf; returned samples remain numeric.
# analysis_operations.write_extrema_results_to_disk(extrema_analysis_results, r'C:\output\extrema.txt')
#
# # E. Changing Display Settings
# display = api.AnalysisDisplaySettings()
# display.constant_color = [1.0, 0.0, 0.0] # Red for extrema points
# analysis_operations.set_display_settings(ext_name, display)
#
# # F. Updating Analysis
# # analysis_operations.update_analysis(ext_name)

5. Gray Value Analysis Workflow​

# # A. Creation
# gray_value_params = api.GrayValueParams()
# gray_value_params.mask_preview_surface_quality = api.Mask3dPreviewQuality.Optimal
# gv_name = analysis_operations.create_gray_value_analysis_mask(
# "GrayValue_Mask_1",
# active_mask_name,
# active_volume_name,
# gray_value_params
# )
#
# # B. Running
# analysis_operations.run_analysis(gv_name)
#
# # C. Getting Info and Results
# analysis_info : api.AnalysisInfo = analysis_operations.get_analysis_info(gv_name)
# print(f"Analysis info: name={analysis_info.name}, type={analysis_info.type}")
#
# gray_value_analysis_results : api.GrayValueAnalysisResults = analysis_operations.get_gray_value_analysis_results(gv_name)
# gray_value_statistics : api.GrayValueAnalysisStatistics = gray_value_analysis_results.statistics
# print(f"Gray Value Mean: {gray_value_statistics.mean_value}")
# for sample in gray_value_analysis_results.samples[:3]:
# gray_value_sample : api.GrayValueSample = sample
# print(f"Gray value sample: {gray_value_sample.value}")
#
# # D. Writing Results to Disk
# # The file classifies values outside the result range as -inf or +inf; returned samples remain numeric.
# analysis_operations.write_gray_value_results_to_disk(gray_value_analysis_results, r'C:\output\gray_value.txt')
#
# # E. Changing Display Settings
# display = api.AnalysisDisplaySettings()
# display.lookup_table_type = api.LookupTableType.ReverseRainbow
# analysis_operations.set_display_settings(gv_name, display)
#
# # F. Updating Analysis
# # analysis_operations.update_analysis(gv_name)

6. Void / Inclusion Analysis Workflow​

# # A. Creation
# void_inclusion_params = api.VoidInclusionParams()
# void_inclusion_params.mode = api.VoidInclusionTargetType.Void
# void_inclusion_params.method = api.VoidInclusionMethod.Absolute
# void_inclusion_params.auto_absolute_contrast = True
# void_inclusion_params.auto_air_gray_value = True
# void_inclusion_params.requested_statistics = [
# "Volume (mm³)",
# "Volume fraction (%)",
# "Centroid X (mm)",
# "Centroid Y (mm)",
# "Centroid Z (mm)",
# "Compactness",
# "Sphericity",
# "Equivalent diameter (mm)"
# ]
#
# void_inclusion_filtering_params = api.VoidInclusionFilteringParams()
# void_inclusion_filtering_params.enable_geometric_filtering = True
# void_inclusion_filtering_params.probability_threshold = 0.0
# void_inclusion_filtering_params.min_voxel_count = 8
# void_inclusion_filtering_params.max_voxel_count = 10000000
# void_inclusion_filtering_params.min_compactness = 0.0
# void_inclusion_filtering_params.max_compactness = 1.0
# void_inclusion_filtering_params.min_sphericity = 0.0
# void_inclusion_filtering_params.max_sphericity = 1.0
# void_inclusion_filtering_params.min_volume_fraction_percent = 0.0
# void_inclusion_filtering_params.max_volume_fraction_percent = 100.0
# void_inclusion_filtering_params.min_equivalent_diameter = 0.0
# void_inclusion_filtering_params.max_equivalent_diameter = 1000000.0
# void_inclusion_filtering_params.max_count = 10000

# void_inclusion_params.filter_result_params = void_inclusion_filtering_params
#
# vi_name = analysis_operations.create_void_inclusion_analysis(
# "VoidInclusion_1",
# active_volume_name,
# "", # No ROI mask
# void_inclusion_params
# )
#
# # B. Running
# if analysis_operations.run_analysis(vi_name):
# print(f"Analysis run successfully: {vi_name}")
# last_mask = app.get_all_mask_names()[len(app.get_all_mask_names())-1]
# app.isolate_masks([last_mask])
# app.set_mask_3d_preview_quality(api.Mask3dPreviewQuality.Optimal)
# app.generate_mask_3d_preview(app.get_visible_mask_names())
#
# # C. Getting Info and Results
# analysis_info : api.AnalysisInfo = analysis_operations.get_analysis_info(vi_name)
# print(f"Analysis info: name={analysis_info.name}, type={analysis_info.type}")
#
# # Get defect results
# void_inclusion_results : api.VoidInclusionResults = analysis_operations.get_void_inclusion_results(vi_name)
# print(f"Void/Inclusion Stats:")
# print(f" Total defects: {void_inclusion_results.total_defects_found}")
# print(f" Total defect volume: {void_inclusion_results.total_defect_volume}")
# print(f" Porosity: {void_inclusion_results.porosity}")
# print(f" Label statistics count: {len(void_inclusion_results.label_statistics)}")
#
# # Get descriptive statistics
# print(f"descriptive_statistics_count: {len(void_inclusion_results.descriptive_statistics)}")
# for item in void_inclusion_results.descriptive_statistics:
# descriptive_statistic : api.VoidInclusionDescriptiveStatistic = item
# stat_type = descriptive_statistic.statistic_type
# std_dev = descriptive_statistic.std_deviation
# print(f"{stat_type}: {std_dev}")
#
# # Get label statistics
# print(f"label_statistics_count: {len(void_inclusion_results.label_statistics)}")
# for item in void_inclusion_results.label_statistics:
# label_statistics : api.VoidInclusionLabelStatistics = item
# label = label_statistics.label
# for stat_item in label_statistics.statistics:
# statistic : api.VoidInclusionStatistic = stat_item
# stat_type = statistic.statistic_type
# value = statistic.values[0] if statistic.values else None
# print(f"{label} | {stat_type}: {value}")
#
# # Get whole-mask statistics
# print(f"whole_mask_statistics_count: {len(void_inclusion_results.whole_mask_statistics)}")
# for item in void_inclusion_results.whole_mask_statistics:
# whole_mask_statistic : api.VoidInclusionWholeMaskStatistic = item
# value = whole_mask_statistic.values[0] if whole_mask_statistic.values else None
# print(f"{whole_mask_statistic.statistic_type}: {value}")
#
# # D. Writing Results to Disk
# analysis_operations.write_void_inclusion_results_to_disk(void_inclusion_results, r'C:\output\void_inclusion.txt')
#
# # E. Changing Display Settings
# display = api.AnalysisDisplaySettings()
# analysis_operations.set_display_settings(vi_name, display)
#
# # F. Updating Analysis
# # analysis_operations.update_analysis(vi_name)

print("Analysis operations tutorial completed successfully.")