├── pzero
├── __init__.py
├── ui
│ ├── __init__.py
│ ├── assign_ui.py
│ ├── README.md
│ └── navigator_window_ui.py
├── views
│ ├── __init__.py
│ └── README.md
├── helpers
│ ├── __init__.py
│ ├── helper_signals.py
│ └── README.md
├── imports
│ ├── __init__.py
│ ├── AbstractImporter.py
│ ├── cesium2vtk.py
│ ├── gltf2vtk.py
│ ├── ply2vtk.py
│ ├── obj2vtk.py
│ ├── dem2vtk.py
│ ├── stl2vtk.py
│ └── README.md
├── collections
│ ├── __init__.py
│ ├── fluid_collection.py
│ ├── background_collection.py
│ ├── geological_collection.py
│ ├── README.md
│ ├── mesh3d_collection.py
│ ├── image_collection.py
│ └── dom_collection.py
├── processing
│ └── README.md
└── README.md
├── style
├── __init__.py
└── imgs
│ ├── __init__.py
│ ├── uparrow2.svg
│ ├── downarrow2.svg
│ ├── leftarrow2.svg
│ └── rightarrow2.svg
├── tests
└── __init__.py
├── old_tests
├── __init__.py
├── test_collections
│ ├── __init__.py
│ ├── test_fluid_collection.py
│ ├── test_background_collection.py
│ ├── test_mesh3d_collection.py
│ ├── test_image_collection.py
│ ├── test_geological_collection.py
│ ├── test_xsection_collection.py
│ ├── test_well_collection.py
│ └── test_dom_collection.py
└── test_helpers
│ ├── __init__.py
│ └── test_helper_dialogs.py
├── gui
├── _use Designer - Form - View Python Code
├── designer.exe - Shortcut.lnk
├── preview_window.ui
└── navigator_window.ui
├── pytest.ini
├── icons
├── dip.png
├── dip_sym.png
├── dip_trasp.png
├── SelectEntity.svg
├── HomeView.svg
├── MergeLines.svg
├── SplitLineLine.svg
├── DrawLine.svg
├── SplitLinePoint.svg
├── RemoveEntity.svg
├── MoveLine.svg
├── ExtendLine.svg
├── BoundaryFrom2Points.svg
├── ExportAsGLTF.svg
├── ExportAsHTML.svg
├── ExportAsOBJ.svg
├── SortLineNodes.svg
├── EditLine.svg
├── ExportAsVTKjs.svg
├── SaveHomeView.svg
├── ClearSelection.svg
├── ZoomToActive.svg
├── dip.svg
├── RotateLine.svg
├── SnapLine.svg
├── ResampleDistance.svg
├── TakeScreenshot.svg
├── ResampleNumber.svg
├── SimplifyLine.svg
├── CopyKink.svg
├── SectionFromAzimuth.svg
└── CleanIntersections.svg
├── images
├── pzero.ico
├── 3d_view.jpg
├── mosaic.jpg
├── PZero_GUI.pptx
├── map_view.jpg
├── pzero_QR.png
├── screenshot.png
├── ArgandStereo.jpg
├── pzero_splash.jpg
├── splash_image.jpg
├── xsection_view.jpg
└── pzero-architecture.jpg
├── envs
├── pzero-env.yml
├── pzero-env-from-history.yml
└── notes_on_pzero_environment_2025-03-12.txt
├── _internal
├── pzero.ico
└── pzero_splash.png
├── docs
├── _static
│ └── .gitignore
├── _templates
│ └── .gitignore
├── index.rst
├── Makefile
├── make.bat
├── pzero.helpers.rst
├── pzero.ui.rst
├── pzero.rst
├── conf.py
├── pzero.imports.rst
└── pzero.collections.rst
├── .ipynb_checkpoints
└── Untitled-checkpoint.ipynb
├── .gitignore
├── helper_scripts
└── vtk_search.py
├── requirements.in
├── .github
├── workflows
│ └── prepare_pr.yml
└── old_workflow
│ ├── class_refactoring_pyside6-testing.yml
│ └── release.yml
└── pzero.py
/pzero/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/style/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/old_tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pzero/ui/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pzero/views/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pzero/helpers/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pzero/imports/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/style/imgs/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/pzero/collections/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/old_tests/test_collections/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/old_tests/test_helpers/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/_use Designer - Form - View Python Code:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | addopts = --ignore=old_tests/
--------------------------------------------------------------------------------
/icons/dip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/icons/dip.png
--------------------------------------------------------------------------------
/images/pzero.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/pzero.ico
--------------------------------------------------------------------------------
/envs/pzero-env.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/envs/pzero-env.yml
--------------------------------------------------------------------------------
/icons/dip_sym.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/icons/dip_sym.png
--------------------------------------------------------------------------------
/images/3d_view.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/3d_view.jpg
--------------------------------------------------------------------------------
/images/mosaic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/mosaic.jpg
--------------------------------------------------------------------------------
/_internal/pzero.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/_internal/pzero.ico
--------------------------------------------------------------------------------
/icons/dip_trasp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/icons/dip_trasp.png
--------------------------------------------------------------------------------
/images/PZero_GUI.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/PZero_GUI.pptx
--------------------------------------------------------------------------------
/images/map_view.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/map_view.jpg
--------------------------------------------------------------------------------
/images/pzero_QR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/pzero_QR.png
--------------------------------------------------------------------------------
/images/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/screenshot.png
--------------------------------------------------------------------------------
/images/ArgandStereo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/ArgandStereo.jpg
--------------------------------------------------------------------------------
/images/pzero_splash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/pzero_splash.jpg
--------------------------------------------------------------------------------
/images/splash_image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/splash_image.jpg
--------------------------------------------------------------------------------
/_internal/pzero_splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/_internal/pzero_splash.png
--------------------------------------------------------------------------------
/images/xsection_view.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/xsection_view.jpg
--------------------------------------------------------------------------------
/docs/_static/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/docs/_templates/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/gui/designer.exe - Shortcut.lnk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/gui/designer.exe - Shortcut.lnk
--------------------------------------------------------------------------------
/images/pzero-architecture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gecos-lab/PZero/HEAD/images/pzero-architecture.jpg
--------------------------------------------------------------------------------
/.ipynb_checkpoints/Untitled-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [],
3 | "metadata": {},
4 | "nbformat": 4,
5 | "nbformat_minor": 5
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /.venv
3 | /pzero/__pycache__
4 | /tests/__pycache__
5 | .DS_Store
6 | *.DS_Store
7 | /installers
8 | *.pyc
9 | /docs/_build
10 | /dist
11 | /build
--------------------------------------------------------------------------------
/pzero/helpers/helper_signals.py:
--------------------------------------------------------------------------------
1 | """helper_signals.py
2 | PZero© Andrea Bistacchi"""
3 |
4 |
5 | def disconnect_all_signals(signals):
6 | """This function disconnects all signals of a QObject"""
7 | for signal in signals:
8 | # for each signal inside the list, disconnect it
9 | signal.disconnect()
10 | return
11 |
--------------------------------------------------------------------------------
/helper_scripts/vtk_search.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from vtkmodules.all import *
3 | import sys
4 |
5 |
6 | lib_dict = globals()
7 |
8 | input_name = sys.argv[1]
9 |
10 | if input_name in lib_dict:
11 | module = lib_dict[input_name]
12 | print(f"from {module.__module__} import {module.__name__}")
13 | else:
14 | print("No module found")
15 |
--------------------------------------------------------------------------------
/requirements.in:
--------------------------------------------------------------------------------
1 | loopstructural
2 | black[d]
3 | cmocean
4 | colorcet
5 | ezdxf
6 | geopandas
7 | laspy
8 | lxml
9 | mplstereonet
10 | openpyxl
11 | pandas
12 | pyinstaller
13 | pyside6
14 | pytest
15 | pyvista
16 | pyvistaqt
17 | qtpy
18 | rasterio
19 | rioxarray
20 | seaborn
21 | segyio
22 | shapely
23 | sphinx
24 | sphinx_rtd_theme
25 | vtk>=9.3, <9.4
26 | xarray
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. PZero documentation master file, created by
2 | sphinx-quickstart on Tue May 2 15:29:51 2023.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to PZero's documentation!
7 | =================================
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 | :caption: Contents:
12 |
13 | modules
14 |
15 | Indices and tables
16 | ==================
17 |
18 | * :ref:`genindex`
19 | * :ref:`modindex`
20 | * :ref:`search`
21 |
--------------------------------------------------------------------------------
/pzero/views/README.md:
--------------------------------------------------------------------------------
1 | # PZero Views Module
2 |
3 | This directory contains the view classes for the PZero application.
4 |
5 | ## Class Hierarchy
6 |
7 | - `BaseView` (abstract_base_view.py): The base class for all views
8 | - `ViewMPL` (abstract_mpl_view.py): Base class for Matplotlib-based views
9 | - `ViewStereoplot` (view_stereoplot.py): Stereoplot view using Matplotlib
10 | - `ViewVTK` (abstract_vtk_view.py): Base class for VTK/PyVista-based views
11 | - `View3D` (view_3d.py): 3D view using VTK/PyVista
12 | - `View2D` (abstract_view_2d.py): Base class for 2D views using VTK/PyVista
13 | - `ViewXsection` (view_xsection.py): Cross-section view
14 | - `ViewMap` (view_map.py): Map view
15 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/pzero/collections/fluid_collection.py:
--------------------------------------------------------------------------------
1 | """fluid_collection.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from .GFB_collection import GFBCollection
5 |
6 |
7 | class FluidCollection(GFBCollection):
8 | """Collection for all fluid entities and their metadata."""
9 |
10 | def __init__(self, parent=None, *args, **kwargs):
11 | super(FluidCollection, self).__init__(parent, *args, **kwargs)
12 | # Initialize properties required by the abstract superclass.
13 | self.valid_roles = [
14 | "undef",
15 | "top",
16 | "base",
17 | "seal",
18 | ]
19 |
20 | self.collection_name = "fluid_coll"
21 |
22 | self.default_sequence = "fluid_0"
23 |
24 | self.initialize_df()
25 |
--------------------------------------------------------------------------------
/pzero/collections/background_collection.py:
--------------------------------------------------------------------------------
1 | """background_collection.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from .GFB_collection import GFBCollection
5 |
6 |
7 | class BackgroundCollection(GFBCollection):
8 | """Collection for all background entities and their metadata."""
9 |
10 | def __init__(self, parent=None, *args, **kwargs):
11 | super(BackgroundCollection, self).__init__(parent, *args, **kwargs)
12 | # Initialize properties required by the abstract superclass.
13 | self.valid_roles = [
14 | "undef",
15 | "annotations",
16 | "imported",
17 | ]
18 |
19 | self.collection_name = "backgrnd_coll"
20 |
21 | self.default_sequence = "back_0"
22 |
23 | self.initialize_df()
24 |
--------------------------------------------------------------------------------
/pzero/imports/AbstractImporter.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractmethod, abstractclassmethod, abstractstaticmethod
2 |
3 |
4 | class BaseIO(ABC):
5 |
6 | def __init__(self, input_file):
7 | self._input_file: str = input_file
8 | self._output_file: str = ""
9 | self._curr_obj = None
10 |
11 | @property
12 | def input_file(self) -> str:
13 | return self._input_file
14 |
15 | @property
16 | def output_file(self) -> str:
17 | return self._output_file
18 |
19 | @output_file.setter
20 | def output_file(self, output_file: str):
21 | self._output_file = output_file
22 |
23 | @abstractmethod
24 | def import_from_file(self):
25 | pass
26 |
27 | @abstractmethod
28 | def output_to_file(self):
29 | pass
30 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | %SPHINXBUILD% >NUL 2>NUL
14 | if errorlevel 9009 (
15 | echo.
16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
17 | echo.installed, then set the SPHINXBUILD environment variable to point
18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
19 | echo.may add the Sphinx directory to PATH.
20 | echo.
21 | echo.If you don't have Sphinx installed, grab it from
22 | echo.https://www.sphinx-doc.org/
23 | exit /b 1
24 | )
25 |
26 | if "%1" == "" goto help
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/pzero/processing/README.md:
--------------------------------------------------------------------------------
1 | # Processing
2 |
3 | This folder contains modules for data processing and standardization tasks within the PZero project, including SEG-Y seismic data standardization and coordinate reference system (CRS) utilities.
4 |
5 | ## File Overview
6 |
7 | - `segy_standardizer.py`
8 | Utility functions for standardizing SEG-Y files to ensure PZero compatibility.
9 | **Main functions:**
10 | - `analyze_segy_parameters(input_file)`: Extracts standard SEG-Y parameters (samples, interval, format, etc.).
11 | - `standardize_segy_for_pzero(input_file, output_file, print_fn=print)`: Converts a SEG-Y file to a standardized format for PZero, updating headers and trace data as needed.
12 | - `convert_to_standard_segy(input_file, output_file, print_fn=print)`: Main entry point for SEG-Y conversion.
13 |
14 | - `CRS.py`
15 | Utilities for handling coordinate reference systems (CRS) and spatial transformations, based on PROJ.
16 | **Typical contents:**
17 | - Functions and/or classes for parsing, converting, and applying CRS definitions to spatial data.
18 |
--------------------------------------------------------------------------------
/docs/pzero.helpers.rst:
--------------------------------------------------------------------------------
1 | pzero.helpers package
2 | =====================
3 |
4 | Submodules
5 | ----------
6 |
7 | pzero.helpers.helper\_dialogs module
8 | ------------------------------------
9 |
10 | .. automodule:: pzero.helpers.helper_dialogs
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | pzero.helpers.helper\_functions module
16 | --------------------------------------
17 |
18 | .. automodule:: pzero.helpers.helper_functions
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | pzero.helpers.helper\_signals module
24 | ------------------------------------
25 |
26 | .. automodule:: pzero.helpers.helper_signals
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | pzero.helpers.helper\_widgets module
32 | ------------------------------------
33 |
34 | .. automodule:: pzero.helpers.helper_widgets
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | Module contents
40 | ---------------
41 |
42 | .. automodule:: pzero.helpers
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
--------------------------------------------------------------------------------
/pzero/collections/geological_collection.py:
--------------------------------------------------------------------------------
1 | """geological_collection.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from .GFB_collection import GFBCollection
5 |
6 |
7 | class GeologicalCollection(GFBCollection):
8 | """Collection for all geological entities and their metadata."""
9 |
10 | def __init__(self, parent=None, *args, **kwargs):
11 | super(GeologicalCollection, self).__init__(parent, *args, **kwargs)
12 | # Initialize properties required by the abstract superclass.
13 | self.valid_roles = [
14 | "undef",
15 | "fault",
16 | "tectonic",
17 | "intrusive",
18 | "unconformity",
19 | "top",
20 | "base",
21 | "bedding",
22 | "foliation",
23 | "lineation",
24 | "axial_surface",
25 | "fold_axis",
26 | "TM_unit",
27 | "TS_unit",
28 | "INT_unit",
29 | "formation",
30 | ]
31 |
32 | self.collection_name = "geol_coll"
33 |
34 | self.default_sequence = "strati_0"
35 |
36 | self.initialize_df()
37 |
--------------------------------------------------------------------------------
/.github/workflows/prepare_pr.yml:
--------------------------------------------------------------------------------
1 | name: Prepare PR
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | prepare:
10 | runs-on: ubuntu-latest
11 | outputs:
12 | changes_detected: ${{ steps.commit.outputs.changes_detected }}
13 | steps:
14 | - uses: actions/checkout@v4
15 | with:
16 | token: ${{ secrets.TOKEN }}
17 | - name: "Get config files from template repository"
18 | run: |
19 | curl -H "Accept: application/vnd.github.VERSION.raw" -H "Authorization: token ${{ secrets.TOKEN }}" https://api.github.com/repos/gecos-lab/templatepythonproject/contents/.pylintrc\?ref\=main > .pylintrc
20 | - name: Black
21 | run: |
22 | pip install black
23 | black .
24 | - uses: stefanzweifel/git-auto-commit-action@v5
25 | id: commit
26 | with:
27 | commit_message: Apply prepare changes
28 | pylint:
29 | needs: prepare
30 | runs-on: ubuntu-latest
31 | steps:
32 | - uses: actions/checkout@v4
33 | - uses: dciborow/action-pylint@main
34 | with:
35 | github_token: ${{ secrets.github_token }}
36 | reporter: github-pr-review
37 | glob_pattern: "**/*.py"
38 |
--------------------------------------------------------------------------------
/envs/pzero-env-from-history.yml:
--------------------------------------------------------------------------------
1 | name: pzero
2 | channels:
3 | - conda-forge
4 | - defaults
5 | dependencies:
6 | - loop3d::loopstructural[version='>=v1.6.3']
7 | - conda-forge::blackd[version='>=23.7.0']
8 | - conda-forge::cmocean
9 | - conda-forge::colorcet
10 | - conda-forge::ezdxf[version='>=1.0.3']
11 | - conda-forge::geopandas[version='>=1.0.1']
12 | - conda-forge::laspy[version='>=2.5.4']
13 | - conda-forge::lxml[version='>=5.3.0']
14 | - conda-forge::mplstereonet[version='>=0.6.3']
15 | - conda-forge::openpyxl[version='>=3.1']
16 | - conda-forge::pandas[version='>=2.2.2']
17 | - conda-forge::pyinstaller[version='>=6']
18 | - conda-forge::pyside6[version='>=6.7.3']
19 | - conda-forge::pytest[version='>=8']
20 | - conda-forge::python[version='>=3.11']
21 | - conda-forge::pyvista[version='>=0.44.1']
22 | - conda-forge::pyvistaqt[version='>=0.11.1']
23 | - conda-forge::qtpy[version='>=2.4']
24 | - conda-forge::rasterio[version='>=1.3.6']
25 | - conda-forge::rioxarray[version='>=0.17.0']
26 | - conda-forge::seaborn
27 | - conda-forge::segyio[version='>=1.9.0']
28 | - conda-forge::shapely[version='>=2.0.6']
29 | - conda-forge::sphinx[version='>=5']
30 | - conda-forge::sphinx_rtd_theme[version='>=2']
31 | - conda-forge::vtk[version='=9.3.1']
32 | - conda-forge::vtk-base[version='=9.3.1']
33 | - conda-forge::xarray[version='>=2023.1.0']
34 |
--------------------------------------------------------------------------------
/docs/pzero.ui.rst:
--------------------------------------------------------------------------------
1 | pzero.ui package
2 | ================
3 |
4 | Submodules
5 | ----------
6 |
7 | pzero.ui.assign\_ui module
8 | --------------------------
9 |
10 | .. automodule:: pzero.ui.assign_ui
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | pzero.ui.base\_view\_window\_ui module
16 | --------------------------------------
17 |
18 | .. automodule:: pzero.ui.base_view_window_ui
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | pzero.ui.import\_window\_ui module
24 | ----------------------------------
25 |
26 | .. automodule:: pzero.ui.import_window_ui
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | pzero.ui.navigator\_window\_ui module
32 | -------------------------------------
33 |
34 | .. automodule:: pzero.ui.navigator_window_ui
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | pzero.ui.preview\_window\_ui module
40 | -----------------------------------
41 |
42 | .. automodule:: pzero.ui.preview_window_ui
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
47 | pzero.ui.project\_window\_ui module
48 | -----------------------------------
49 |
50 | .. automodule:: pzero.ui.project_window_ui
51 | :members:
52 | :undoc-members:
53 | :show-inheritance:
54 |
55 | Module contents
56 | ---------------
57 |
58 | .. automodule:: pzero.ui
59 | :members:
60 | :undoc-members:
61 | :show-inheritance:
62 |
--------------------------------------------------------------------------------
/pzero.py:
--------------------------------------------------------------------------------
1 | """pzero.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from sys import argv, exit, platform
5 |
6 | from PySide6.QtWidgets import QApplication, QSplashScreen
7 | from PySide6.QtGui import QPixmap
8 |
9 | # from PySide6.QtCore import Qt
10 |
11 | # if hasattr(Qt, 'AA_EnableHighDpiScaling'):
12 | # QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
13 | #
14 | # if hasattr(Qt, 'AA_UseHighDpiPixmaps'):
15 | # QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
16 |
17 | # Start Qt application
18 | app = QApplication(argv)
19 |
20 | # Use Fusion style: this is a uniform style for all platforms, but the
21 | # real reason to use it is that the standard Windows 11 style has some bug
22 | # in Qt 6.7.2, including one related to tear-off submenus.
23 | # if platform == 'darwin':
24 | # elif platform == 'win32':
25 | # elif platform == 'linux':
26 | app.setStyle("Fusion")
27 | # app.setStyle('windows11')
28 | # app.setStyle('windowsvista')
29 | # app.setStyle('windows')
30 |
31 | # Display splash screen before doing anything else
32 | splash_image = QPixmap("_internal/pzero_splash.png")
33 | splash = QSplashScreen(splash_image)
34 | splash.show()
35 |
36 | # Load all libraries
37 | from pzero.project_window import ProjectWindow
38 |
39 | # Create project window and project
40 | project_window = ProjectWindow()
41 |
42 | # Show project window and close splash screen
43 | project_window.show()
44 | splash.finish(project_window)
45 |
46 | # This is to clean everything when exiting
47 | exit(app.exec_())
48 |
--------------------------------------------------------------------------------
/pzero/collections/README.md:
--------------------------------------------------------------------------------
1 | # Collections
2 |
3 | This folder contains classes for managing different types of collections and their metadata in PZero.
4 |
5 | ## Class Hierarchy
6 |
7 | - `BaseCollection`
8 | _Abstract base class for all collection types. Defines the common interface and required methods using ABC._
9 | _(Defined in `AbstractCollection.py`.)_
10 |
11 | - `WellCollection`
12 | _Manages a collection of wells and their metadata._
13 | _(Defined in `well_collection.py`.)_
14 |
15 | - `DIMCollection`
16 | _Intermediate base class for collections of DOM, Image and Mesh3d entities._
17 | _(Defined in `DIM_collection.py`.)_
18 |
19 | - `DomCollection`
20 | _Manages a collection of DOM entities and their metadata._
21 | _(Defined in `dom_collection.py`.)_
22 |
23 | - `ImageCollection`
24 | _Manages a collection of image entities and their metadata._
25 | _(Defined in `image_collection.py`.)_
26 |
27 | - `Mesh3DCollection`
28 | _Manages a collection of 3D mesh entities and their metadata._
29 | _(Defined in `mesh3d_collection.py`.)_
30 |
31 | - `GFBCollection`
32 | _Intermediate abstract class used as a base for geological, fluid, and background collections._
33 | _(Defined in `GFB_collection.py`.)_
34 |
35 | - `GeologicalCollection`
36 | _Manages a collection of geological entities and their metadata._
37 | _(Defined in `geological_collection.py`.)_
38 |
39 | - `FluidCollection`
40 | _Manages a collection of fluid entities and their metadata._
41 | _(Defined in `fluid_collection.py`.)_
42 |
43 | - `BackgroundCollection`
44 | _Manages a collection of background entities and their metadata._
45 | _(Defined in `background_collection.py`.)_
46 |
--------------------------------------------------------------------------------
/pzero/ui/assign_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'assign_data.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9.2
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 |
12 | class Ui_AssignWindow(object):
13 | def setupUi(self, AssignWindow):
14 | AssignWindow.setObjectName("AssignWindow")
15 | AssignWindow.resize(450, 620)
16 | self.AssignLayout = QtWidgets.QWidget(AssignWindow)
17 | self.AssignLayout.setObjectName("AssignLayout")
18 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.AssignLayout)
19 | self.verticalLayout_2.setObjectName("verticalLayout_2")
20 | self.AssignTable = QtWidgets.QTableWidget(self.AssignLayout)
21 | self.AssignTable.setObjectName("AssignTable")
22 | self.AssignTable.setColumnCount(0)
23 | self.AssignTable.setRowCount(0)
24 | self.AssignTable.verticalHeader().setVisible(True)
25 | self.verticalLayout_2.addWidget(self.AssignTable)
26 | self.ConfirmButton = QtWidgets.QDialogButtonBox(self.AssignLayout)
27 | self.ConfirmButton.setStandardButtons(
28 | QtWidgets.QDialogButtonBox.Close | QtWidgets.QDialogButtonBox.Ok
29 | )
30 | self.ConfirmButton.setCenterButtons(True)
31 | self.ConfirmButton.setObjectName("ConfirmButton")
32 | self.verticalLayout_2.addWidget(self.ConfirmButton)
33 | AssignWindow.setCentralWidget(self.AssignLayout)
34 |
35 | self.retranslateUi(AssignWindow)
36 | QtCore.QMetaObject.connectSlotsByName(AssignWindow)
37 |
38 | def retranslateUi(self, AssignWindow):
39 | _translate = QtCore.QCoreApplication.translate
40 | AssignWindow.setWindowTitle(_translate("AssignWindow", "Assign data"))
41 |
--------------------------------------------------------------------------------
/pzero/imports/cesium2vtk.py:
--------------------------------------------------------------------------------
1 | """cesium2vtk.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from vtk import vtkCesium3DTilesWriter, vtkMultiBlockDataSet
5 |
6 | from pzero.entities_factory import TriSurf
7 |
8 |
9 | def vtk2cesium(self=None, out_dir_name=None):
10 | """Exports all triangulated surfaces to a collection of GLTF binary surfaces (extension .glb).
11 | Note that saving in binary format is automatically set by using the .glb extension.
12 | https://vtk.org/doc/nightly/html//classvtkCesium3DTilesWriter.html
13 | https://github.com/Kitware/VTK/blob/master/IO/Geometry/vtkGLTFWriter.cxx
14 |
15 | https://github.com/Kitware/Danesfield/blob/master/tools/tiler.py
16 | https://github.com/Kitware/Danesfield/blob/master/tools/tiler-test.sh
17 |
18 | IN THE FUTURE extend to other entity classes such as DEM, polyline, etc."""
19 | # File name
20 | out_file_name = str(out_dir_name) + "/" + "multi_block_dataset" + ".glb"
21 | # Create GLTF writer.
22 | multi_block = vtkMultiBlockDataSet()
23 | print("multi_block: ", multi_block)
24 | writer = vtkCesium3DTilesWriter()
25 | print("writer: ", writer)
26 | # Loop for each entity.
27 | i = 0
28 | for uid in self.geol_coll.df["uid"]:
29 | if isinstance(self.geol_coll.get_uid_vtk_obj(uid), TriSurf):
30 | print("i: ", i)
31 | vtk_entity = self.geol_coll.get_uid_vtk_obj(uid)
32 | multi_block.SetBlock(i, vtk_entity)
33 | print("multi_block: ", multi_block)
34 | i = i + 1
35 |
36 | writer.SetInputDataObject(multi_block)
37 | writer.SetDirectoryName(out_dir_name)
38 | writer.SetTextureBaseDirectory(out_dir_name)
39 | writer.SetInputType(2)
40 | writer.SetContentGLTF(True)
41 | crs = "+proj=utm +zone=32 +north +datum=WGS84"
42 | writer.SetCRS(crs)
43 | print("writer: ", writer)
44 | writer.Write()
45 |
46 | print("All TSurfs saved.")
47 |
--------------------------------------------------------------------------------
/pzero/collections/mesh3d_collection.py:
--------------------------------------------------------------------------------
1 | """mesh3d_collection.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from .DIM_collection import DIMCollection
5 |
6 |
7 | class Mesh3DCollection(DIMCollection):
8 | """Collection for all mesh entities and their metadata."""
9 |
10 | def __init__(self, parent=None, *args, **kwargs):
11 | super(Mesh3DCollection, self).__init__(parent, *args, **kwargs)
12 | # Initialize properties required by the abstract superclass.
13 | self.entity_dict = {
14 | "uid": "",
15 | "name": "undef",
16 | "scenario": "undef",
17 | "parent_uid": "", # this is the uid of the cross section for "XsVertexSet", "XsPolyLine", and "XsImage", empty for all others
18 | "topology": "undef",
19 | "vtk_obj": None,
20 | "properties_names": [],
21 | "properties_components": [],
22 | "properties_types": [],
23 | }
24 |
25 | self.entity_dict_types = {
26 | "uid": str,
27 | "name": str,
28 | "scenario": str,
29 | "parent_uid": str,
30 | "topology": str,
31 | "vtk_obj": object,
32 | "properties_names": list,
33 | "properties_components": list,
34 | "properties_types": list,
35 | }
36 |
37 | self.valid_topologies = ["TetraSolid", "Voxet", "XsVoxet"]
38 |
39 | self.collection_name = "mesh3d_coll"
40 |
41 | self.default_colormap = "rainbow"
42 |
43 | self.initialize_df()
44 |
45 | # =================================== Obligatory methods ===========================================
46 |
47 | def get_uid_legend(self, uid: str = None) -> dict:
48 | """Get legend for a particular uid."""
49 | legend_dict = self.parent.others_legend_df.loc[
50 | self.parent.others_legend_df["other_collection"] == "Mesh3D"
51 | ].to_dict("records")
52 | return legend_dict[0]
53 |
--------------------------------------------------------------------------------
/pzero/collections/image_collection.py:
--------------------------------------------------------------------------------
1 | """image_collection.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from .DIM_collection import DIMCollection
5 |
6 |
7 | class ImageCollection(DIMCollection):
8 | """Collection for all image entities and their metadata."""
9 |
10 | def __init__(self, parent=None, *args, **kwargs):
11 | super(ImageCollection, self).__init__(parent, *args, **kwargs)
12 | # Initialize properties required by the abstract superclass.
13 | self.entity_dict = {
14 | "uid": "",
15 | "name": "undef",
16 | "scenario": "undef",
17 | "parent_uid": "", # this is the uid of the cross section for "XsVertexSet", "XsPolyLine", and "XsImage", empty for all others
18 | "topology": "undef",
19 | "vtk_obj": None,
20 | "properties_names": [],
21 | "properties_components": [],
22 | "properties_types": [],
23 | }
24 |
25 | self.entity_dict_types = {
26 | "uid": str,
27 | "name": str,
28 | "scenario": str,
29 | "parent_uid": str,
30 | "topology": str,
31 | "vtk_obj": object,
32 | "properties_names": list,
33 | "properties_components": list,
34 | "properties_types": list,
35 | }
36 |
37 | self.valid_topologies = [
38 | "MapImage",
39 | "XsImage",
40 | "Seismics",
41 | "Image3D",
42 | ]
43 |
44 | self.collection_name = "image_coll"
45 |
46 | self.default_colormap = "gray"
47 |
48 | self.initialize_df()
49 |
50 | # =================================== Obligatory methods ===========================================
51 |
52 | def get_uid_legend(self, uid: str = None) -> dict:
53 | """Get legend for a particular uid."""
54 | legend_dict = self.parent.others_legend_df.loc[
55 | self.parent.others_legend_df["other_collection"] == "Image"
56 | ].to_dict("records")
57 | return legend_dict[0]
58 |
--------------------------------------------------------------------------------
/old_tests/test_collections/test_fluid_collection.py:
--------------------------------------------------------------------------------
1 | from pzero.collections.fluid_collection import FluidCollection
2 | from pzero.legend_manager import Legend
3 | from pzero.entities_factory import DEM
4 |
5 | from pandas import DataFrame as pd_DataFrame
6 | from PySide6.QtWidgets import QMainWindow
7 |
8 |
9 | # Class used as a substitute of pyqt-signals/emit
10 | class FakeSignal:
11 | def emit(self, uid):
12 | return
13 |
14 |
15 | # Class used as a substitute of Legend
16 | class FakeLegend:
17 | def update_widget(self, parent):
18 | return
19 |
20 |
21 | # Class used for test the main window (project_window) as a parent
22 | class FakeWindow(QMainWindow):
23 | def __init__(self):
24 | super(FakeWindow, self).__init__()
25 |
26 | fluidss_coll.legend_df = pd_DataFrame(
27 | columns=list(Legend.fluids_legend_dict.keys())
28 | )
29 | legend = FakeLegend()
30 | prop_legend = FakeLegend()
31 | fluid_coll.signals.added = FakeSignal()
32 | fluid_coll.signals.removed = FakeSignal()
33 | fluid_coll = FluidCollection()
34 |
35 |
36 | class TestFluidCollection:
37 | fluid_coll_istance = FluidCollection(FakeWindow)
38 | test_vtk_obj = DEM()
39 | test_vtk_obj2 = DEM()
40 | entity_dict = {
41 | "uid": "4",
42 | "name": "fluid-test",
43 | "topology": "undef",
44 | "role": "undef",
45 | "feature": "undef",
46 | "scenario": "undef",
47 | "properties_names": [],
48 | "properties_components": [],
49 | "x_section": "",
50 | "vtk_obj": test_vtk_obj,
51 | }
52 |
53 | def test_add_entity_from_dict(self):
54 | # add an entity
55 | self.fluid_coll_istance.add_entity_from_dict(self.entity_dict)
56 |
57 | # check if the entities number is equal to the add_entity calls
58 | # and if the uid inserted is in the uids of the collection
59 | assert (
60 | self.fluid_coll_istance.get_number_of_entities() == 1
61 | and self.entity_dict["uid"] in self.fluid_coll_istance.get_uids()
62 | )
63 |
--------------------------------------------------------------------------------
/docs/pzero.rst:
--------------------------------------------------------------------------------
1 | pzero package
2 | =============
3 |
4 | Subpackages
5 | -----------
6 |
7 | .. toctree::
8 | :maxdepth: 4
9 |
10 | pzero.collections
11 | pzero.helpers
12 | pzero.imports
13 | pzero.ui
14 |
15 | Submodules
16 | ----------
17 |
18 | pzero.entities\_factory module
19 | ------------------------------
20 |
21 | .. automodule:: pzero.entities_factory
22 | :members:
23 | :undoc-members:
24 | :show-inheritance:
25 |
26 | pzero.legend\_manager module
27 | ----------------------------
28 |
29 | .. automodule:: pzero.legend_manager
30 | :members:
31 | :undoc-members:
32 | :show-inheritance:
33 |
34 | pzero.orientation\_analysis module
35 | ----------------------------------
36 |
37 | .. automodule:: pzero.orientation_analysis
38 | :members:
39 | :undoc-members:
40 | :show-inheritance:
41 |
42 | pzero.point\_clouds module
43 | --------------------------
44 |
45 | .. automodule:: pzero.point_clouds
46 | :members:
47 | :undoc-members:
48 | :show-inheritance:
49 |
50 | pzero.project\_window module
51 | ----------------------------
52 |
53 | .. automodule:: pzero.project_window
54 | :members:
55 | :undoc-members:
56 | :show-inheritance:
57 |
58 | pzero.properties\_manager module
59 | --------------------------------
60 |
61 | .. automodule:: pzero.properties_manager
62 | :members:
63 | :undoc-members:
64 | :show-inheritance:
65 |
66 | pzero.three\_d\_surfaces module
67 | -------------------------------
68 |
69 | .. automodule:: pzero.three_d_surfaces
70 | :members:
71 | :undoc-members:
72 | :show-inheritance:
73 |
74 | pzero.two\_d\_lines module
75 | --------------------------
76 |
77 | .. automodule:: pzero.two_d_lines
78 | :members:
79 | :undoc-members:
80 | :show-inheritance:
81 |
82 | pzero.windows\_factory module
83 | -----------------------------
84 |
85 | .. automodule:: pzero.windows_factory
86 | :members:
87 | :undoc-members:
88 | :show-inheritance:
89 |
90 | Module contents
91 | ---------------
92 |
93 | .. automodule:: pzero
94 | :members:
95 | :undoc-members:
96 | :show-inheritance:
97 |
--------------------------------------------------------------------------------
/icons/SelectEntity.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
51 |
--------------------------------------------------------------------------------
/old_tests/test_collections/test_background_collection.py:
--------------------------------------------------------------------------------
1 | from pzero.collections.background_collection import BackgroundCollection
2 | from pzero.legend_manager import Legend
3 |
4 | from pandas import DataFrame as pd_DataFrame
5 | from PySide6.QtWidgets import QMainWindow
6 |
7 | # Global Variable
8 | entity_dict = {
9 | "uid": "53",
10 | "name": "background-test",
11 | "topology": "undef",
12 | "role": "undef",
13 | "feature": "undef",
14 | "properties_names": [],
15 | "properties_components": [],
16 | "x_section": "",
17 | "borehole": "",
18 | "vtk_obj": None,
19 | }
20 |
21 |
22 | # Class used as a substitute of pyqt-signals/emit
23 | class FakeSignal:
24 | def emit(self, uid):
25 | return
26 |
27 |
28 | # Class used as a substitute of Legend
29 | class FakeLegend:
30 | def update_widget(self, parent):
31 | return
32 |
33 |
34 | # Class used as a substitute of BackgroundCollection
35 | class FakeBGCollection:
36 | df = pd_DataFrame(columns=list(entity_dict.keys()))
37 |
38 |
39 | # Class used for test the main window (project_window) as a parent
40 | class FakeWindow(QMainWindow):
41 | def __init__(self):
42 | super(FakeWindow, self).__init__()
43 |
44 | backgrnd_coll.legend_df = pd_DataFrame(
45 | columns=list(Legend.backgrounds_legend_dict.keys())
46 | )
47 | backgrnd_coll = FakeBGCollection()
48 |
49 | legend = FakeLegend()
50 | prop_legend = FakeLegend()
51 |
52 | backgrnd_coll.signals.added = FakeSignal()
53 | backgrnd_coll.signals.removed = FakeSignal()
54 |
55 |
56 | class TestBackgroundCollection:
57 | background_coll_istance = BackgroundCollection(FakeWindow)
58 |
59 | def test_add_entity_from_dict(self):
60 | # add an entity
61 | self.background_coll_istance.add_entity_from_dict(entity_dict)
62 |
63 | # check if the entities number is equal to the add_entity calls
64 | # and if the uid inserted is in the uids of the collection
65 | assert (
66 | self.background_coll_istance.get_number_of_entities() == 1
67 | and entity_dict["uid"] in self.background_coll_istance.get_uids()
68 | )
69 |
--------------------------------------------------------------------------------
/icons/HomeView.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
57 |
--------------------------------------------------------------------------------
/icons/MergeLines.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
54 |
--------------------------------------------------------------------------------
/icons/SplitLineLine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
61 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 | #
13 | import os
14 | import sys
15 |
16 | sys.path.insert(0, os.path.abspath(".."))
17 |
18 |
19 | # -- Project information -----------------------------------------------------
20 |
21 | project = "PZero"
22 | copyright = "2020, Andrea Bistacchi"
23 | author = "Andrea Bistacchi"
24 |
25 | # The full version, including alpha/beta/rc tags
26 | release = "0.0.1"
27 |
28 |
29 | # -- General configuration ---------------------------------------------------
30 |
31 | # Add any Sphinx extension module names here, as strings. They can be
32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
33 | # ones.
34 | extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode", "sphinx.ext.napoleon"]
35 |
36 | # Add any paths that contain templates here, relative to this directory.
37 | templates_path = ["_templates"]
38 |
39 | # List of patterns, relative to source directory, that match files and
40 | # directories to ignore when looking for source files.
41 | # This pattern also affects html_static_path and html_extra_path.
42 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
43 |
44 |
45 | # -- Options for HTML output -------------------------------------------------
46 |
47 | # The theme to use for HTML and HTML Help pages. See the documentation for
48 | # a list of builtin themes.
49 | #
50 | html_theme = "sphinx_rtd_theme"
51 |
52 | # Add any paths that contain custom static files (such as style sheets) here,
53 | # relative to this directory. They are copied after the builtin static files,
54 | # so a file named "default.css" will overwrite the builtin "default.css".
55 | html_static_path = ["_static"]
56 |
--------------------------------------------------------------------------------
/icons/DrawLine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
51 |
--------------------------------------------------------------------------------
/old_tests/test_collections/test_mesh3d_collection.py:
--------------------------------------------------------------------------------
1 | from pzero.collections.mesh3d_collection import Mesh3DCollection
2 |
3 | from PySide6.QtWidgets import QMainWindow
4 |
5 |
6 | # Class used as a substitute of pyqt-signals/emit
7 | class FakeSignal:
8 | def emit(self, uid):
9 | return
10 |
11 |
12 | # Class used as a substitute of Legend
13 | class FakeLegend:
14 | def update_widget(self, parent):
15 | return
16 |
17 |
18 | # Class used for test the main window (project_window) as a parent
19 | class FakeWindow(QMainWindow):
20 | def __init__(self):
21 | super(FakeWindow, self).__init__()
22 |
23 | mesh3d_coll.signals.added = FakeSignal()
24 | mesh3d_coll.signals.removed = FakeSignal()
25 | prop_legend = FakeLegend()
26 |
27 |
28 | class TestMesh3dCollection:
29 | mesh_3d_coll_istance = Mesh3DCollection(FakeWindow)
30 |
31 | entity_dict = {
32 | "uid": "0",
33 | "name": "meshtest",
34 | "topology": "undef",
35 | "properties_names": [],
36 | "properties_components": [],
37 | "x_section": "",
38 | "vtk_obj": None,
39 | }
40 |
41 | def test_add_entity_from_dict(self):
42 | # add an entity
43 | self.mesh_3d_coll_istance.add_entity_from_dict(self.entity_dict)
44 |
45 | # check if the entities number is equal to the add_entity calls
46 | # and if the uid inserted is in the uids of the collection
47 | assert (
48 | self.mesh_3d_coll_istance.get_number_of_entities() == 1
49 | and self.entity_dict["uid"] in self.mesh_3d_coll_istance.get_uids()
50 | )
51 |
52 | def test_remove_entity(self):
53 | # add an entity
54 | self.mesh_3d_coll_istance.add_entity_from_dict(self.entity_dict)
55 |
56 | # remove an entity
57 | self.mesh_3d_coll_istance.remove_entity(self.entity_dict["uid"])
58 |
59 | # check if the entities number is equal to the add_entity calls minus the remove_entity calls
60 | # and if the uid inserted and then removed is not in the uids of the collection
61 | assert (
62 | self.mesh_3d_coll_istance.get_number_of_entities() == 0
63 | and self.entity_dict["uid"] not in self.mesh_3d_coll_istance.get_uids()
64 | )
65 |
--------------------------------------------------------------------------------
/old_tests/test_collections/test_image_collection.py:
--------------------------------------------------------------------------------
1 | from pzero.collections.image_collection import ImageCollection
2 | from pzero.collections.dom_collection import DomCollection
3 |
4 | from PySide6.QtWidgets import QMainWindow
5 |
6 |
7 | # Class used as a substitute of pyqt-signals/emit
8 | class FakeSignal:
9 | def emit(self, uid):
10 | return
11 |
12 |
13 | # Class used as a substitute of Legend
14 | class FakeLegend:
15 | def update_widget(self, parent):
16 | return
17 |
18 |
19 | # Class used for test the main window (project_window) as a parent
20 | class FakeWindow(QMainWindow):
21 | def __init__(self):
22 | super(FakeWindow, self).__init__()
23 |
24 | image_coll.signals.added = FakeSignal()
25 | image_coll.signals.removed = FakeSignal()
26 | dom_coll = DomCollection()
27 | prop_legend = FakeLegend()
28 |
29 |
30 | class TestXSectionCollection:
31 | image_coll_istance = ImageCollection(FakeWindow)
32 |
33 | entity_dict = {
34 | "uid": "22",
35 | "name": "image-test",
36 | "topology": "undef",
37 | "properties_names": [],
38 | "properties_components": [],
39 | "properties_types": [],
40 | "x_section": "",
41 | "vtk_obj": None,
42 | }
43 |
44 | def test_add_entity_from_dict(self):
45 | # add an entity
46 | self.image_coll_istance.add_entity_from_dict(self.entity_dict)
47 |
48 | # check if the entities number is equal to the add_entity calls
49 | # and if the uid inserted is in the uids of the collection
50 | assert (
51 | self.image_coll_istance.get_number_of_entities() == 1
52 | and self.entity_dict["uid"] in self.image_coll_istance.get_uids()
53 | )
54 |
55 | def test_remove_entity(self):
56 | # add an entity
57 | self.image_coll_istance.add_entity_from_dict(self.entity_dict)
58 |
59 | # remove an entity
60 | self.image_coll_istance.remove_entity(self.entity_dict["uid"])
61 |
62 | # check if the entities number is equal to the add_entity calls minus the remove_entity calls
63 | # and if the uid inserted and then removed is not in the uids of the collection
64 | assert [
65 | self.entity_dict["uid"]
66 | ] not in self.image_coll_istance.get_uids() and self.image_coll_istance.get_number_of_entities() == 0
67 |
--------------------------------------------------------------------------------
/pzero/imports/gltf2vtk.py:
--------------------------------------------------------------------------------
1 | """gltf2vtk.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from vtk import vtkGLTFWriter, vtkMultiBlockDataSet
5 |
6 | from pzero.entities_factory import TriSurf
7 |
8 |
9 | def vtk2gltf(self=None, out_dir_name=None):
10 | """Exports all triangulated surfaces to a collection of GLTF binary surfaces (extension .glb).
11 | Note that saving in binary format is automatically set by using the .glb extension.
12 | IN THE FUTURE extendo to other entity classes such as DEM, polyline, etc."""
13 | # File name
14 | out_file_name = str(out_dir_name) + "/" + "multi_block_dataset" + ".glb"
15 | # Create GLTF writer.
16 | multi_block = vtkMultiBlockDataSet()
17 | writer = vtkGLTFWriter()
18 | # Loop for each entity.
19 | i = 0
20 | for uid in self.geol_coll.df["uid"]:
21 | if isinstance(self.geol_coll.get_uid_vtk_obj(uid), TriSurf):
22 | vtk_entity = self.geol_coll.get_uid_vtk_obj(uid)
23 | multi_block.SetBlock(i, vtk_entity)
24 | i = i + 1
25 | # for uid in self.boundary_coll.df['uid']:
26 | # if isinstance(self.boundary_coll.get_uid_vtk_obj(uid), TriSurf):
27 | # vtk_entity = self.boundary_coll.get_uid_vtk_obj(uid)
28 | # multi_block.SetBlock(i, vtk_entity)
29 | # i = i + 1
30 | writer.InlineDataOff()
31 | # writer.SetTextureBaseDirectory(str(out_dir_name))
32 | # SetPropertyTextureFile(const char *)
33 | writer.SaveNormalOn()
34 | writer.SaveTexturesOn()
35 | # writer.CopyTexturesOn() # AttributeError: 'vtkmodules.vtkIOGeometry.vtkGLTFWriter' object has no attribute 'CopyTexturesOn'
36 | # writer.SaveActivePointColorOn() # saves RGB is an active 3 or 4 component scalar field is found
37 | # writer.RelativeCoordinatesOn() # Save mesh point coordinates relative to the bounding box origin and add the corresponding translation to the root node - AttributeError: 'vtkmodules.vtkIOGeometry.vtkGLTFWriter' object has no attribute 'RelativeCoordinatesOn'
38 | # writer.SetRelativeCoordinates(True) # AttributeError: 'vtkmodules.vtkIOGeometry.vtkGLTFWriter' object has no attribute 'SetRelativeCoordinates'
39 | writer.SetInputDataObject(multi_block)
40 | # writer.SetDirectoryName(out_dir_name)
41 | writer.SetFileName(out_file_name)
42 | print("test - writer: ", writer)
43 | writer.Write()
44 |
45 | print("All TSurfs saved.")
46 |
--------------------------------------------------------------------------------
/gui/preview_window.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | PreviewWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 845
10 | 538
11 |
12 |
13 |
14 | Preview Window
15 |
16 |
17 |
18 | -
19 |
20 |
21 |
22 | 0
23 | 0
24 |
25 |
26 |
27 |
-
28 |
29 |
30 | 3
31 |
32 |
33 |
34 | -
35 |
36 |
37 | Preview
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 | 0
46 | 0
47 |
48 |
49 |
50 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
51 |
52 |
53 | false
54 |
55 |
56 |
57 |
58 |
59 |
60 | -
61 |
62 |
63 |
-
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/icons/SplitLinePoint.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
59 |
--------------------------------------------------------------------------------
/pzero/helpers/README.md:
--------------------------------------------------------------------------------
1 | # Helpers
2 |
3 | This folder contains utility classes and functions that support interactive widgets, color management, signal handling, dialogs, and general helper routines for the PZero project.
4 |
5 | ## File Overview
6 |
7 | - `helper_widgets.py`
8 | Provides interactive VTK-based widgets for tracing, vector drawing, editing, and cutting lines in 3D scenes.
9 | **Main classes:**
10 | - `Tracer`: For drawing freehand lines.
11 | - `Vector`: For drawing and measuring vectors (length, azimuth, dip).
12 | - `Editor`: For editing and extending polylines interactively.
13 | - `Scissors`: For interactively cutting lines.
14 |
15 | - `helper_colors.py`
16 | Utilities for color conversion, palette management, and color-related helpers.
17 |
18 | - `helper_functions.py`
19 | General-purpose helper functions for profiling, math, geometry, and data manipulation.
20 | **Main functions:**
21 | - `profiler`: Decorator for profiling function execution time.
22 | - `angle_wrapper`: Wraps angles to \[0, 2π\].
23 | - `PCA`: Principal Component Analysis on data arrays.
24 | - `best_fitting_plane`: Computes the best fitting plane for a set of 3D points.
25 | - `gen_frame`: Generates transparent frames for GIFs.
26 | - `rotate_vec_along`: Rotates a vector along a specified axis.
27 | - `srf`: Computes the mean resultant length of vectors.
28 | - `freeze_gui`: Decorator to freeze GUI during processing.
29 |
30 | - `helper_widgets_qt.py`
31 | Qt-based widget helpers for integrating custom controls and dialogs into the GUI.
32 |
33 | - `helper_signals.py`
34 | Utilities for managing Qt signals, such as disconnecting all signals from a list.
35 | **Main function:**
36 | - `disconnect_all_signals(signals)`: Disconnects all signals of a QObject.
37 |
38 | - `helper_dialogs.py`
39 | Dialog utilities for user input, file selection, progress, and data preview.
40 | **Main functions/classes:**
41 | - `options_dialog`, `input_text_dialog`, `input_combo_dialog`, `open_file_dialog`, etc.: Various input and message dialogs.
42 | - `multiple_input_dialog`, `general_input_dialog`, `input_checkbox_dialog`: Flexible dialogs for multiple or custom inputs.
43 | - `progress_dialog`: Progress bar dialog for long-running tasks.
44 | - `PCDataModel`: Qt table model for displaying pandas DataFrames.
45 | - `import_dialog`: Window for importing and previewing data files.
46 | - `NavigatorWidget`, `PreviewWidget`: Widgets for navigation and previewing data/meshes.
47 |
--------------------------------------------------------------------------------
/icons/RemoveEntity.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
61 |
--------------------------------------------------------------------------------
/gui/navigator_window.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | NavWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 540
10 | 95
11 |
12 |
13 |
14 |
15 | 540
16 | 90
17 |
18 |
19 |
20 |
21 | 562
22 | 95
23 |
24 |
25 |
26 | Navigator
27 |
28 |
29 |
30 | -
31 |
32 |
33 |
34 | 0
35 | 0
36 |
37 |
38 |
39 |
40 | 540
41 | 45
42 |
43 |
44 |
45 |
46 | 815
47 | 65
48 |
49 |
50 |
51 |
-
52 |
53 |
54 | >>
55 |
56 |
57 |
58 | -
59 |
60 |
61 | <<
62 |
63 |
64 |
65 | -
66 |
67 |
68 | Qt::LeftToRight
69 |
70 |
71 |
72 |
73 |
74 | Qt::AlignCenter
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/icons/MoveLine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
69 |
--------------------------------------------------------------------------------
/pzero/ui/README.md:
--------------------------------------------------------------------------------
1 | # UI
2 |
3 | This folder contains user interface (UI) modules for the PZero project. These modules define the graphical and interactive components of the application using PySide6. Generally the UI files are created with Designer and converted to Python code.
4 |
5 | ## File Overview
6 |
7 | - `project_window_ui.py`
8 | Auto-generated Python code from a Qt Designer `.ui` file for the main project window.
9 | Defines the layout, menus, actions, and widgets for the main application interface, including tables, tabs, and toolbars for managing geology, fluids, backgrounds, DEMs/DOMs, images, meshes, boundaries, cross-sections, wells, legends, properties, and a terminal.
10 |
11 | - `preview_window_ui.py`
12 | Auto-generated Python code from a Qt Designer `.ui` file for the preview window.
13 | Defines the layout and widgets for a preview dialog, including options, a preview button, OK/Cancel buttons, and a preview display area.
14 |
15 | - `navigator_window_ui.py`
16 | Auto-generated Python code from a Qt Designer `.ui` file for the navigator window.
17 | Provides a minimal navigation interface with forward/back buttons and a section label, typically used for navigating between sections or steps in the application.
18 |
19 | - `import_window_ui.py`
20 | Auto-generated Python code from a Qt Designer `.ui` file for the import options window.
21 | Defines the layout and widgets for importing data, including data preview, assignment tables, file path selection, separator options, and import controls.
22 |
23 | - `dock_view_ui.py`
24 | Auto-generated Python code from a Qt Designer `.ui` file for the dockable view window.
25 | Provides a split interface with a toolbox for navigating geology, topology, cross-sections, boundaries, meshes, DEMs/DOMs, wells, fluids, backgrounds, and images, alongside a main view frame for displaying content.
26 |
27 | - `base_view_window_ui.py`
28 | Auto-generated Python code from a Qt Designer `.ui` file for the base view window.
29 | Defines a main window with a horizontal splitter: a main view frame and a toolbox for navigating geology, fluids, backgrounds, DEMs/DOMs, images, meshes, boundaries, cross-sections, and wells. Includes a menu bar and status bar.
30 |
31 | - `assign_ui.py`
32 | Auto-generated Python code from a Qt Designer `.ui` file for the assign data window.
33 | Provides a main window with a table for data assignment and a dialog button box for confirming or closing the assignment.
34 |
35 | - `__init__.py`
36 | Marks the folder as a Python package.
37 | May contain package-level imports or initialization code (often empty).
38 |
--------------------------------------------------------------------------------
/pzero/imports/ply2vtk.py:
--------------------------------------------------------------------------------
1 | """ply2vtk.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from vtk import vtkPLYWriter
5 |
6 | from pzero.entities_factory import TriSurf
7 |
8 |
9 | def vtk2ply(self=None, out_dir_name=None):
10 | """Exports all triangulated surfaces to a collection of PLY surfaces.
11 | IN THE FUTURE extend to other entity classes such as DEM, polyline, etc."""
12 | # Create PLY writer.
13 | ply_writer = vtkPLYWriter()
14 | ply_writer.SetFileTypeToBinary()
15 | ply_writer.SetColorModeToUniformCellColor()
16 | # Loop for each entity.
17 | for uid in self.geol_coll.df["uid"]:
18 | if isinstance(self.geol_coll.get_uid_vtk_obj(uid), TriSurf):
19 | out_file_name = (
20 | str(out_dir_name)
21 | + "/"
22 | + uid
23 | + "_"
24 | + self.geol_coll.df.loc[self.geol_coll.df["uid"] == uid, "name"].values[
25 | 0
26 | ]
27 | + ".stl"
28 | )
29 | vtk_entity = self.geol_coll.get_uid_vtk_obj(uid)
30 | color_R = self.geol_coll.get_uid_legend(uid=uid)["color_R"]
31 | color_G = self.geol_coll.get_uid_legend(uid=uid)["color_G"]
32 | color_B = self.geol_coll.get_uid_legend(uid=uid)["color_B"]
33 | print("RGB: ", color_R, color_G, color_B)
34 | ply_writer.SetFileName(out_file_name)
35 | ply_writer.SetInputData(vtk_entity)
36 | ply_writer.SetColor(color_R, color_G, color_B)
37 | ply_writer.Write()
38 | for uid in self.boundary_coll.df["uid"]:
39 | if isinstance(self.boundary_coll.get_uid_vtk_obj(uid), TriSurf):
40 | out_file_name = (
41 | str(out_dir_name)
42 | + "/"
43 | + uid
44 | + "_"
45 | + self.boundary_coll.df.loc[
46 | self.boundary_coll.df["uid"] == uid, "name"
47 | ].values[0]
48 | + ".stl"
49 | )
50 | vtk_entity = self.boundary_coll.get_uid_vtk_obj(uid)
51 | color_R = self.boundary_coll.get_uid_legend(uid=uid)["color_R"]
52 | color_G = self.boundary_coll.get_uid_legend(uid=uid)["color_G"]
53 | color_B = self.boundary_coll.get_uid_legend(uid=uid)["color_B"]
54 | print("RGB: ", color_R, color_G, color_B)
55 | ply_writer.SetFileName(out_file_name)
56 | ply_writer.SetInputData(vtk_entity)
57 | ply_writer.SetColor(color_R, color_G, color_B)
58 | ply_writer.Write()
59 | print("All TSurfs saved.")
60 |
--------------------------------------------------------------------------------
/icons/ExtendLine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
65 |
--------------------------------------------------------------------------------
/icons/BoundaryFrom2Points.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
64 |
--------------------------------------------------------------------------------
/envs/notes_on_pzero_environment_2025-03-12.txt:
--------------------------------------------------------------------------------
1 | ===================================
2 | Notes on pzero conda environments
3 |
4 | THIS DOCUMENT MUST BE KEPT UPDATED!
5 | ===================================
6 |
7 | _______________________
8 | Last updated 2025-03-12
9 |
10 |
11 | 1) To build a clean pzero environment, start updating the conda base environment:
12 |
13 | conda activate base
14 | conda update -n base -c conda-forge conda
15 | conda update --all
16 |
17 | (sometimes repeating this more than once helps to have a completely up-to-date base environment)
18 |
19 | 3) Then remove any old pzero environment, e.g.:
20 |
21 | conda remove --name pzero --all
22 |
23 | 4) Install packages (from within ./PZero/envs directory):
24 |
25 | conda env create -n pzero -f ./pzero-env.yml
26 |
27 | or
28 |
29 | conda env create -n pzero -f ./pzero-env-from-history.yml
30 |
31 | The former includes all packages with specific releases, while the latter includes only requirements listed in pzero-env-from-history.yml.
32 |
33 | The logic in the second case is to have the most recent versions as possible, or at least well proven ones (>=), with exceptions (strictly =) motivated in the issues.
34 |
35 | Note that version requirements are easily recorded/updated by editing the pzero-env-from-history.yml file and then regenerating the environment as above.
36 |
37 | For some strange reason, openpyxl (used to import Excel files) is required by pandas but not automatically added with its dependencies, so we have to add it explicitly to the environment.
38 |
39 | Additional modules that where explicitly required in the past, but apparently not now, are pillow>=9.5.0, pythreejs>=2.4.2, and vedo.
40 |
41 | This has been tested on Windows 11 and macOS 15 so far.
42 |
43 | On macOS it is possible that conda fails to detect the right version of the OS. In this case it is necessary to force the __osx variable with:
44 |
45 | conda env config vars set CONDA_OVERRIDE_OSX="11"
46 |
47 | Then the value of __osx can be checked with:
48 |
49 | conda info
50 |
51 | 5) Finally record the environment in .yml files (from within ./PZero/envs directory):
52 |
53 | conda env export --from-history > ./pzero-env-from-history.yml
54 |
55 | and
56 |
57 | conda env export > ./pzero-env.yml
58 |
59 | This allows a quick installation with (from within ./PZero/envs directory):
60 |
61 | conda env create -n pzero -f ./pzero-env.yml
62 |
63 |
64 |
65 | * In case a new empty environment must be created, use:
66 |
67 | conda create -n pzero
68 |
69 | * In case a channels must be activated (this must be done for each new environment):
70 |
71 | conda config --env --add channels conda-forge
72 | conda config --env --add channels loop3d
73 | conda config --env --add channels anaconda
--------------------------------------------------------------------------------
/pzero/imports/obj2vtk.py:
--------------------------------------------------------------------------------
1 | """obj2vtk.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from vtk import vtkOBJWriter
5 | from pzero.entities_factory import TriSurf
6 | from pzero.helpers.helper_dialogs import options_dialog
7 |
8 |
9 | def vtk2obj(self=None, out_dir_name=None):
10 | """Exports all triangulated surfaces to a collection of OBJ surfaces.
11 | IN THE FUTURE extendo to other entity classes such as DEM, polyline, etc."""
12 | # At the moment only entities in the geological collection can be exported.
13 | if self.shown_table != "tabGeology":
14 | return
15 | append_name = options_dialog(
16 | title="Append name",
17 | message="Append entity name to output file name?",
18 | yes_role="Yes",
19 | no_role="No",
20 | reject_role=None,
21 | )
22 | if append_name == 0:
23 | append_name = True
24 | else:
25 | append_name = False
26 | # Create STL writer.
27 | obj_writer = vtkOBJWriter()
28 | # Loop for each entity.
29 | for uid in self.selected_uids:
30 | if isinstance(self.geol_coll.get_uid_vtk_obj(uid), TriSurf):
31 | if append_name:
32 | out_file_name = (
33 | str(out_dir_name)
34 | + "/"
35 | + uid
36 | + "_"
37 | + self.geol_coll.df.loc[
38 | self.geol_coll.df["uid"] == uid, "name"
39 | ].values[0]
40 | + ".obj"
41 | )
42 | else:
43 | out_file_name = str(out_dir_name) + "/" + uid + ".obj"
44 | vtk_entity = self.geol_coll.get_uid_vtk_obj(uid)
45 | obj_writer.SetFileName(out_file_name)
46 | obj_writer.SetInputData(vtk_entity)
47 | obj_writer.Write()
48 | # for uid in self.selected_uids:
49 | # if isinstance(self.boundary_coll.get_uid_vtk_obj(uid), TriSurf):
50 | # if append_name:
51 | # out_file_name = (
52 | # str(out_dir_name)
53 | # + "/"
54 | # + uid
55 | # + "_"
56 | # + self.boundary_coll.df.loc[
57 | # self.boundary_coll.df["uid"] == uid, "name"
58 | # ].values[0]
59 | # + ".obj"
60 | # )
61 | # else:
62 | # out_file_name = str(out_dir_name) + "/" + uid + ".obj"
63 | # vtk_entity = self.boundary_coll.get_uid_vtk_obj(uid)
64 | # obj_writer.SetFileName(out_file_name)
65 | # obj_writer.SetInputData(vtk_entity)
66 | # obj_writer.Write()
67 | # print("All TSurfs saved.")
68 |
--------------------------------------------------------------------------------
/old_tests/test_collections/test_geological_collection.py:
--------------------------------------------------------------------------------
1 | from pzero.collections.geological_collection import GeologicalCollection
2 | from pzero.legend_manager import Legend
3 |
4 | from pandas import DataFrame as pd_DataFrame
5 | from PySide6.QtWidgets import QMainWindow
6 |
7 |
8 | # Class used as a substitute of pyqt-signals/emit
9 | class FakeSignal:
10 | def emit(self, uid):
11 | return
12 |
13 |
14 | # Class used as a substitute of Legend
15 | class FakeLegend:
16 | def update_widget(self, parent):
17 | return
18 |
19 |
20 | # Class used for test the main window (project_window) as a parent
21 | class FakeWindow(QMainWindow):
22 | def __init__(self):
23 | super(FakeWindow, self).__init__()
24 |
25 | geol_coll.legend_df = pd_DataFrame(columns=list(Legend.geol_legend_dict.keys()))
26 | legend = FakeLegend()
27 | prop_legend = FakeLegend()
28 | geol_coll.signals.added = FakeSignal()
29 | geol_coll.signals.removed = FakeSignal()
30 |
31 |
32 | # Class for testing geological_collection.py
33 | class TestGeologicalCollection:
34 | geo_coll_istance = GeologicalCollection(FakeWindow)
35 |
36 | geological_entity_dict1 = {
37 | "uid": "0",
38 | "name": "geoname",
39 | "topology": "topol",
40 | "role": "undef",
41 | "feature": "undef",
42 | "scenario": "sc1",
43 | "properties_names": [],
44 | "properties_components": [],
45 | "x_section": "",
46 | "vtk_obj": None,
47 | }
48 |
49 | geological_entity_dict2 = {
50 | "uid": "2",
51 | "name": "geoname2",
52 | "topology": "topol2",
53 | "role": "undef",
54 | "feature": "undef",
55 | "scenario": "sc2",
56 | "properties_names": [],
57 | "properties_components": [],
58 | "x_section": "",
59 | "vtk_obj": None,
60 | }
61 |
62 | # Test the add_entity_from_dict() method from geological_collection.py
63 | def test_add_entity_from_dict(self):
64 | # Add two entities
65 | self.geo_coll_istance.add_entity_from_dict(
66 | entity_dict=self.geological_entity_dict1
67 | )
68 | self.geo_coll_istance.add_entity_from_dict(
69 | entity_dict=self.geological_entity_dict2
70 | )
71 |
72 | # This print should be the same as the entity_dict
73 | # print(geo_coll_istance.df)
74 |
75 | assert (
76 | self.geo_coll_istance.get_number_of_entities() == 2
77 | and (
78 | self.geological_entity_dict1["uid"] in self.geo_coll_istance.get_uids()
79 | )
80 | and (
81 | self.geological_entity_dict2["uid"] in self.geo_coll_istance.get_uids()
82 | )
83 | )
84 |
--------------------------------------------------------------------------------
/icons/ExportAsGLTF.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
69 |
--------------------------------------------------------------------------------
/icons/ExportAsHTML.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
69 |
--------------------------------------------------------------------------------
/icons/ExportAsOBJ.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
69 |
--------------------------------------------------------------------------------
/icons/SortLineNodes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
75 |
--------------------------------------------------------------------------------
/pzero/imports/dem2vtk.py:
--------------------------------------------------------------------------------
1 | """dem2vtk.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | import os
5 |
6 | from uuid import uuid4
7 |
8 | from copy import deepcopy
9 |
10 | from rioxarray import open_rasterio as rx_open_rasterio
11 |
12 | from numpy import meshgrid as np_meshgrid
13 |
14 | from pyvista import StructuredGrid as pv_StructuredGrid
15 |
16 | from pzero.collections.dom_collection import DomCollection
17 | from pzero.collections.fluid_collection import FluidCollection
18 | from pzero.entities_factory import DEM
19 |
20 |
21 | def dem2vtk(self=None, in_file_name=None, collection=None):
22 | """Import and add a DEM structured grid to the dom_coll of the project.
23 | is the calling ProjectWindow() instance."""
24 | # Read raster file format (geotiff) with xarray and rasterio and create DEM structured grid.
25 | # Helpful: http://xarray.pydata.org/en/stable/auto_gallery/plot_rasterio.html
26 | # https://github.com/pyvista/pyvista-support/issues/205, thanks to Bane Sullivan
27 | data = rx_open_rasterio(in_file_name)
28 | values = data.values[0]
29 | # nans = values == data.nodatavals
30 | # if np_any(nans):
31 | # values[nans] = np_nan
32 | xx, yy = np_meshgrid(data["x"], data["y"])
33 | zz = values.reshape(xx.shape)
34 | # Convert to DEM() instance.
35 | curr_obj = DEM()
36 | temp_obj = pv_StructuredGrid(xx, yy, zz)
37 | temp_obj["elevation"] = zz.ravel(order="F")
38 | curr_obj.ShallowCopy(temp_obj)
39 | curr_obj.Modified()
40 | # Create dictionary.
41 | if collection == "DEMs and DOMs":
42 | curr_obj_attributes = deepcopy(DomCollection().entity_dict)
43 | curr_obj_attributes["uid"] = str(uuid4())
44 | curr_obj_attributes["name"] = os.path.basename(in_file_name)
45 | curr_obj_attributes["topology"] = "DEM"
46 | curr_obj_attributes["textures"] = []
47 | curr_obj_attributes["properties_names"] = ["elevation"]
48 | curr_obj_attributes["properties_components"] = [1]
49 | curr_obj_attributes["vtk_obj"] = curr_obj
50 | # Add to entity collection.
51 | self.dom_coll.add_entity_from_dict(entity_dict=curr_obj_attributes)
52 | elif collection == "Fluid contacts":
53 | curr_obj_attributes = deepcopy(FluidCollection.entity_dict)
54 | curr_obj_attributes["uid"] = str(uuid4())
55 | curr_obj_attributes["name"] = os.path.basename(in_file_name)
56 | curr_obj_attributes["role"] = "raster"
57 | curr_obj_attributes["textures"] = []
58 | curr_obj_attributes["properties_names"] = ["elevation"]
59 | curr_obj_attributes["properties_components"] = [1]
60 | curr_obj_attributes["vtk_obj"] = curr_obj
61 | # Add to entity collection.
62 | self.fluid_coll.add_entity_from_dict(entity_dict=curr_obj_attributes)
63 | # Cleaning.
64 | del curr_obj
65 | del curr_obj_attributes
66 |
--------------------------------------------------------------------------------
/icons/EditLine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
69 |
--------------------------------------------------------------------------------
/icons/ExportAsVTKjs.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
71 |
--------------------------------------------------------------------------------
/docs/pzero.imports.rst:
--------------------------------------------------------------------------------
1 | pzero.imports package
2 | =====================
3 |
4 | Submodules
5 | ----------
6 |
7 | pzero.imports.dem2vtk module
8 | ----------------------------
9 |
10 | .. automodule:: pzero.imports.dem2vtk
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | pzero.imports.dxf2vtk module
16 | ----------------------------
17 |
18 | .. automodule:: pzero.imports.dxf2vtk
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | pzero.imports.gocad2vtk module
24 | ------------------------------
25 |
26 | .. automodule:: pzero.imports.gocad2vtk
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | pzero.imports.image2vtk module
32 | ------------------------------
33 |
34 | .. automodule:: pzero.imports.image2vtk
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | pzero.imports.lxml2vtk module
40 | -----------------------------
41 |
42 | .. automodule:: pzero.imports.lxml2vtk
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
47 | pzero.imports.obj2vtk module
48 | ----------------------------
49 |
50 | .. automodule:: pzero.imports.obj2vtk
51 | :members:
52 | :undoc-members:
53 | :show-inheritance:
54 |
55 | pzero.imports.pc2vtk module
56 | ---------------------------
57 |
58 | .. automodule:: pzero.imports.pc2vtk
59 | :members:
60 | :undoc-members:
61 | :show-inheritance:
62 |
63 | pzero.imports.ply2vtk module
64 | ----------------------------
65 |
66 | .. automodule:: pzero.imports.ply2vtk
67 | :members:
68 | :undoc-members:
69 | :show-inheritance:
70 |
71 | pzero.imports.pyvista2vtk module
72 | --------------------------------
73 |
74 | .. automodule:: pzero.imports.pyvista2vtk
75 | :members:
76 | :undoc-members:
77 | :show-inheritance:
78 |
79 | pzero.imports.segy2vtk module
80 | -----------------------------
81 |
82 | .. automodule:: pzero.imports.segy2vtk
83 | :members:
84 | :undoc-members:
85 | :show-inheritance:
86 |
87 | pzero.imports.shp2vtk module
88 | ----------------------------
89 |
90 | .. automodule:: pzero.imports.shp2vtk
91 | :members:
92 | :undoc-members:
93 | :show-inheritance:
94 |
95 | pzero.imports.stl2vtk module
96 | ----------------------------
97 |
98 | .. automodule:: pzero.imports.stl2vtk
99 | :members:
100 | :undoc-members:
101 | :show-inheritance:
102 |
103 | pzero.imports.vedo2vtk module
104 | -----------------------------
105 |
106 | .. automodule:: pzero.imports.vedo2vtk
107 | :members:
108 | :undoc-members:
109 | :show-inheritance:
110 |
111 | pzero.imports.well2vtk module
112 | -----------------------------
113 |
114 | .. automodule:: pzero.imports.well2vtk
115 | :members:
116 | :undoc-members:
117 | :show-inheritance:
118 |
119 | Module contents
120 | ---------------
121 |
122 | .. automodule:: pzero.imports
123 | :members:
124 | :undoc-members:
125 | :show-inheritance:
126 |
--------------------------------------------------------------------------------
/icons/SaveHomeView.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
68 |
--------------------------------------------------------------------------------
/icons/ClearSelection.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
64 |
--------------------------------------------------------------------------------
/old_tests/test_collections/test_xsection_collection.py:
--------------------------------------------------------------------------------
1 | from pzero.collections.xsection_collection import XSectionCollection
2 | from PySide6.QtWidgets import QMainWindow
3 |
4 |
5 | # Class used as a substitute of pyqt-signals/emit
6 | class FakeSignal:
7 | def emit(self, uid):
8 | return
9 |
10 |
11 | # Class used as a substitute of Legend
12 | class FakeLegend:
13 | def update_widget(self, parent):
14 | return
15 |
16 |
17 | # Class used for test the main window (project_window) as a parent
18 | class FakeWindow(QMainWindow):
19 | def __init__(self):
20 | super(FakeWindow, self).__init__()
21 |
22 | xsect_coll.signals.added = FakeSignal()
23 | xsect_coll.signals.removed = FakeSignal()
24 |
25 |
26 | class TestXSectionCollection:
27 | entity_dict = {
28 | "uid": "0",
29 | "name": "geoname",
30 | "topology": "topol",
31 | "role": "undef",
32 | "feature": "undef",
33 | "scenario": "sc1",
34 | "properties_names": [],
35 | "properties_components": [],
36 | "x_section": "",
37 | "vtk_obj": None,
38 | }
39 |
40 | x_section_coll_istance = XSectionCollection(FakeWindow)
41 |
42 | def test_add_entity_from_dict(self):
43 | # add an entity
44 | self.x_section_coll_istance.add_entity_from_dict(self.entity_dict)
45 |
46 | # check if the entities number is equal to the add_entity calls
47 | # and if the uid inserted is in the uids of the collection
48 | assert (
49 | self.x_section_coll_istance.get_number_of_entities() == 1
50 | and self.entity_dict["uid"] in self.x_section_coll_istance.get_uids()
51 | )
52 |
53 | def test_remove_entity(self):
54 | # add an entity
55 | self.x_section_coll_istance.add_entity_from_dict(self.entity_dict)
56 |
57 | # remove an entity
58 | self.x_section_coll_istance.remove_entity(self.entity_dict["uid"])
59 |
60 | # check if the entities number is equal to the add_entity calls minus the remove_entity calls
61 | # and if the uid inserted and then removed is not in the uids of the collection
62 | assert (
63 | self.x_section_coll_istance.get_number_of_entities() == 0
64 | and self.entity_dict["uid"] not in self.x_section_coll_istance.get_uids()
65 | )
66 |
67 | def test_set_parameters_in_table(self):
68 | # add an entity
69 | self.x_section_coll_istance.add_entity_from_dict(self.entity_dict)
70 |
71 | self.x_section_coll_istance.set_parameters_in_table(
72 | uid="2",
73 | name="name-test",
74 | base_point=[0, 1, 10],
75 | end_point=[0, 1, 2],
76 | normal=[0, 1, 2],
77 | azimuth=None,
78 | length=None,
79 | top=None,
80 | bottom=None,
81 | )
82 |
83 | assert (
84 | self.x_section_coll_istance.get_number_of_entities() == 1
85 | and self.entity_dict["uid"] in self.x_section_coll_istance.get_uids()
86 | )
87 |
--------------------------------------------------------------------------------
/.github/old_workflow/class_refactoring_pyside6-testing.yml:
--------------------------------------------------------------------------------
1 | name: Unit Testing
2 |
3 | on:
4 | push:
5 | branches:
6 | - 'class_refactoring_pyside6'
7 |
8 |
9 | jobs:
10 | # Linux
11 | linux-testing:
12 | name: Linux Unit Testing
13 | runs-on: ubuntu-latest
14 | defaults:
15 | run:
16 | shell: bash -el {0}
17 | permissions:
18 | checks: write
19 | pull-requests: write
20 |
21 |
22 | steps:
23 | - name: Checkout Repo
24 | uses: actions/checkout@v3
25 |
26 | - name: Create Environment from .yml
27 | uses: conda-incubator/setup-miniconda@v2
28 | with:
29 | #mamba-version: "*"
30 | channels: conda-forge,defaults
31 | channel-priority: true
32 | activate-environment: pzero-testing
33 | environment-file: envs/pzero-env.yml
34 | # python-version: 3.8.16
35 | python-version: 3.12
36 | auto-activate-base: false
37 |
38 | - name: Check Conda Dependencies
39 | run: |
40 | conda info
41 | conda list
42 |
43 | - name: Test with pytest
44 | run: |
45 | conda install pytest-html
46 | pytest --html=ubu-test-report.html tests/
47 |
48 | - name: Upload pytest test results
49 | uses: actions/upload-artifact@v3
50 | with:
51 | name: pytest-results-ubuntu
52 | path: ubu-test-report.html
53 | # Use always() to always run this step to publish test results when there are test failures
54 | if: ${{ always() }}
55 |
56 |
57 | # Windows
58 | windows-testing:
59 | name: Windows Unit Testing
60 | runs-on: windows-latest
61 | defaults:
62 | run:
63 | shell: bash -el {0}
64 | permissions:
65 | checks: write
66 | pull-requests: write
67 |
68 | steps:
69 | - name: Checkout Repo
70 | uses: actions/checkout@v3
71 |
72 | - name: Create Environment from .yml
73 | uses: conda-incubator/setup-miniconda@v2
74 | with:
75 | #mamba-version: "*"
76 | channels: conda-forge,defaults
77 | channel-priority: true
78 | activate-environment: pzero-test
79 | environment-file: envs/pzero-env.yml
80 | # python-version: 3.8.16
81 | python-version: 3.12
82 | auto-activate-base: false
83 |
84 | - name: Check Conda Dependencies
85 | run: |
86 | conda info
87 | conda list
88 |
89 | - name: Test with pytest
90 | run: |
91 | conda install pytest-html
92 | pytest --html=win-test-report.html tests/
93 |
94 | - name: Upload pytest test results
95 | uses: actions/upload-artifact@v3
96 | with:
97 | name: pytest-results-win
98 | path: win-test-report.html
99 | # Use always() to always run this step to publish test results when there are test failures
100 | if: ${{ always() }}
101 |
--------------------------------------------------------------------------------
/icons/ZoomToActive.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
78 |
--------------------------------------------------------------------------------
/icons/dip.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
80 |
--------------------------------------------------------------------------------
/icons/RotateLine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
83 |
--------------------------------------------------------------------------------
/icons/SnapLine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
70 |
--------------------------------------------------------------------------------
/old_tests/test_collections/test_well_collection.py:
--------------------------------------------------------------------------------
1 | from pzero.collections.well_collection import WellCollection
2 | from pzero.entities_factory import Well
3 | from pzero.entities_factory import PolyLine
4 | from pzero.legend_manager import Legend
5 |
6 | from pandas import DataFrame as pd_DataFrame
7 | from PySide6.QtWidgets import QMainWindow
8 |
9 |
10 | # Class used as a substitute of pyqt-signals/emit
11 | class FakeSignal:
12 | def emit(self, uid):
13 | return
14 |
15 |
16 | # Class used as a substitute of Legend
17 | class FakeLegend:
18 | def update_widget(self, parent):
19 | return
20 |
21 |
22 | # Class used for test the main window (project_window) as a parent
23 | class FakeWindow(QMainWindow):
24 | def __init__(self):
25 | super(FakeWindow, self).__init__()
26 |
27 | legend = FakeLegend()
28 | prop_legend = FakeLegend()
29 | well_legend_df = pd_DataFrame(columns=list(Legend.well_legend_dict.keys()))
30 | well_coll.signals.added = FakeSignal()
31 | well_coll.signals.removed = FakeSignal()
32 |
33 |
34 | class TestWellConnection:
35 | vtk_obj = PolyLine()
36 | vtk_obj2 = Well().trace
37 | well_istance = WellCollection(FakeWindow)
38 |
39 | well_entity_dict_1 = {
40 | "uid": "14",
41 | "Loc ID": "3",
42 | "properties_names": [],
43 | "properties_components": [],
44 | "properties_types": [],
45 | "markers": [],
46 | "vtk_obj": vtk_obj,
47 | }
48 |
49 | def test_add_entity_from_dict(self):
50 | # add an entity
51 | self.well_istance.add_entity_from_dict(self.well_entity_dict_1)
52 |
53 | # check if the entities number is equal to the add_entity calls
54 | # and if the uid inserted is in the uids of the collection
55 | assert (
56 | self.well_istance.get_number_of_entities() == 1
57 | and self.well_entity_dict_1["uid"] in self.well_istance.get_uids()
58 | )
59 |
60 | def test_remove_entity(self):
61 | # add an entity
62 | self.well_istance.add_entity_from_dict(self.well_entity_dict_1)
63 |
64 | # remove an entity
65 | self.well_istance.remove_entity(self.well_entity_dict_1["uid"])
66 |
67 | # check if the entities number is equal to the add_entity calls minus the remove_entity calls
68 | # and if the uid inserted and then removed is not in the uids of the collection
69 | assert (
70 | self.well_istance.get_number_of_entities() == 0
71 | and self.well_entity_dict_1["uid"] not in self.well_istance.get_uids()
72 | )
73 |
74 | def test_replace_vtk(self):
75 | # add an entity
76 | self.well_istance.add_entity_from_dict(self.well_entity_dict_1)
77 |
78 | # replace the vtk obj of the entity added
79 | self.well_istance.replace_vtk(
80 | uid=self.well_entity_dict_1["uid"], vtk_object=self.vtk_obj2
81 | )
82 |
83 | # check if the entities number is equal to the add_entity calls
84 | # and if the vtk obj inserted is in the uids of the collection
85 | assert (
86 | self.well_istance.get_number_of_entities() == 1
87 | and self.well_istance.get_uid_vtk_obj(self.well_entity_dict_1["uid"])
88 | == self.vtk_obj2
89 | )
90 |
--------------------------------------------------------------------------------
/old_tests/test_collections/test_dom_collection.py:
--------------------------------------------------------------------------------
1 | from pzero.collections.dom_collection import DomCollection
2 | from pzero.legend_manager import Legend
3 | from pzero.entities_factory import DEM
4 |
5 | from pandas import DataFrame as pd_DataFrame
6 | from PySide6.QtWidgets import QMainWindow
7 |
8 |
9 | # Class used as a substitute of pyqt-signals/emit
10 | class FakeSignal:
11 | def emit(self, uid):
12 | return
13 |
14 |
15 | # Class used as a substitute of Legend
16 | class FakeLegend:
17 | def update_widget(self, parent):
18 | return
19 |
20 |
21 | # Class used for test the main window (project_window) as a parent
22 | class FakeWindow(QMainWindow):
23 |
24 | def __init__(self):
25 | super(FakeWindow, self).__init__()
26 |
27 | backgrnd_coll.legend_df = pd_DataFrame(
28 | columns=list(Legend.backgrounds_legend_dict.keys())
29 | )
30 | legend = FakeLegend()
31 | prop_legend = FakeLegend()
32 | dom_coll.signals.added = FakeSignal()
33 | dom_coll.signals.removed = FakeSignal()
34 |
35 |
36 | # Class for testing the dom_collection
37 | class TestDomCollection:
38 | test_vtk_obj = DEM()
39 | test_vtk_obj2 = DEM()
40 | entity_dict = {
41 | "uid": "0",
42 | "name": "geoname",
43 | "topology": "topol",
44 | "role": "undef",
45 | "feature": "undef",
46 | "scenario": "sc1",
47 | "properties_names": [],
48 | "properties_components": [],
49 | "x_section": "",
50 | "vtk_obj": test_vtk_obj,
51 | }
52 |
53 | dom_istance = DomCollection(FakeWindow)
54 |
55 | def test_add_entity_from_dict(self):
56 | # add an entity
57 | self.dom_istance.add_entity_from_dict(self.entity_dict)
58 |
59 | # check if the entities number is equal to the add_entity calls
60 | # and if the uid inserted is in the uids of the collection
61 | assert (
62 | self.dom_istance.get_number_of_entities() == 1
63 | and self.entity_dict["uid"] in self.dom_istance.get_uids()
64 | )
65 |
66 | def test_remove_entity(self):
67 | # add an entity
68 | self.dom_istance.add_entity_from_dict(self.entity_dict)
69 |
70 | # remove an entity
71 | self.dom_istance.remove_entity(self.entity_dict["uid"])
72 |
73 | # check if the entities number is equal to the add_entity calls minus the remove_entity calls
74 | # and if the uid inserted and then removed is not in the uids of the collection
75 | assert (
76 | self.dom_istance.get_number_of_entities() == 0
77 | and self.entity_dict["uid"] not in self.dom_istance.get_uids()
78 | )
79 |
80 | def test_replace_vtk(self):
81 | # add an entity
82 | self.dom_istance.add_entity_from_dict(self.entity_dict)
83 |
84 | # replace the vtk obj of the entity added
85 | self.dom_istance.replace_vtk(
86 | uid=self.entity_dict["uid"], vtk_object=self.test_vtk_obj2
87 | )
88 |
89 | # check if the entities number is equal to the add_entity calls
90 | # and if the vtk obj inserted is in the uids of the collection
91 | assert (
92 | self.dom_istance.get_number_of_entities() == 1
93 | and self.dom_istance.get_uid_vtk_obj(self.entity_dict["uid"])
94 | == self.test_vtk_obj2
95 | )
96 |
--------------------------------------------------------------------------------
/docs/pzero.collections.rst:
--------------------------------------------------------------------------------
1 | pzero.collections package
2 | =========================
3 | One of the most important groups of files comprises the "collections." Each collection encapsulates all entities of a specific type of geological or non-geological objects, such as images that indirectly assist in describing a geological model. These collections are always Pandas dataframes. Inside each "type_of_collection.py" file, we have a series of similar methods that serve to manage the entities, including:
4 |
5 | -add_entity(): Takes an entity as input and inserts it into the entity list of that collection.
6 |
7 | -remove_entity(): Removes a specific entity from a collection using its UID.
8 |
9 | -clone_entity(): Duplicates and adds the same input entity to a collection.
10 |
11 | -replace_vtk(): Given a UID, replaces the vtk instance of that entity with another input instance.
12 |
13 | Many getter and setter methods for retrieving and setting UIDs, properties, metadata, etc.
14 | Another group of files is used within "project_windows.py," comprising around fifteen small files that contain all the useful functions for converting, importing, and exporting various formats to be used in the View.
15 |
16 | Submodules
17 | ----------
18 |
19 | pzero.collections.background\_collection module
20 | -----------------------------------------------
21 |
22 | .. automodule:: pzero.collections.background_collection
23 | :members:
24 | :undoc-members:
25 | :show-inheritance:
26 |
27 | pzero.collections.boundary\_collection module
28 | ---------------------------------------------
29 |
30 | .. automodule:: pzero.collections.boundary_collection
31 | :members:
32 | :undoc-members:
33 | :show-inheritance:
34 |
35 | pzero.collections.dom\_collection module
36 | ----------------------------------------
37 |
38 | .. automodule:: pzero.collections.dom_collection
39 | :members:
40 | :undoc-members:
41 | :show-inheritance:
42 |
43 | pzero.collections.fluid\_collection module
44 | ------------------------------------------
45 |
46 | .. automodule:: pzero.collections.fluid_collection
47 | :members:
48 | :undoc-members:
49 | :show-inheritance:
50 |
51 | pzero.collections.geological\_collection module
52 | -----------------------------------------------
53 |
54 | .. automodule:: pzero.collections.geological_collection
55 | :members:
56 | :undoc-members:
57 | :show-inheritance:
58 |
59 | pzero.collections.image\_collection module
60 | ------------------------------------------
61 |
62 | .. automodule:: pzero.collections.image_collection
63 | :members:
64 | :undoc-members:
65 | :show-inheritance:
66 |
67 | pzero.collections.mesh3d\_collection module
68 | -------------------------------------------
69 |
70 | .. automodule:: pzero.collections.mesh3d_collection
71 | :members:
72 | :undoc-members:
73 | :show-inheritance:
74 |
75 | pzero.collections.well\_collection module
76 | -----------------------------------------
77 |
78 | .. automodule:: pzero.collections.well_collection
79 | :members:
80 | :undoc-members:
81 | :show-inheritance:
82 |
83 | pzero.collections.xsection\_collection module
84 | ---------------------------------------------
85 |
86 | .. automodule:: pzero.collections.xsection_collection
87 | :members:
88 | :undoc-members:
89 | :show-inheritance:
90 |
91 | Module contents
92 | ---------------
93 |
94 | .. automodule:: pzero.collections
95 | :members:
96 | :undoc-members:
97 | :show-inheritance:
98 |
--------------------------------------------------------------------------------
/icons/ResampleDistance.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
79 |
--------------------------------------------------------------------------------
/.github/old_workflow/release.yml:
--------------------------------------------------------------------------------
1 | name: Deploy and Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - v*.*.*
7 |
8 | jobs:
9 | # Specify the reusable workflow
10 | testing:
11 | uses: ./.github/old_workflow/release-testing.yml
12 |
13 | deploy:
14 | strategy:
15 | matrix:
16 | # OS we can use to run jobs
17 | os: [windows-latest, ubuntu-latest, macos-latest]
18 |
19 | defaults:
20 | run:
21 | shell: bash -el {0}
22 | permissions:
23 | checks: write
24 | pull-requests: write
25 |
26 | runs-on: ${{ matrix.os }}
27 | # Requiring one or more reusable old_workflow in needs
28 | needs: [testing]
29 |
30 | # Steps for deploying a release
31 | steps:
32 | - name: Checkout Repo
33 | uses: actions/checkout@v3
34 |
35 | - name: Install Conda Env
36 | # Use the following if condition to generate os-specific envs
37 | # if: ${{ matrix.os == 'macos-latest' }}
38 | # if: ${{ matrix.os != 'macos-latest' }}
39 | uses: conda-incubator/setup-miniconda@v2
40 | with:
41 | mamba-version: "*"
42 | channels: conda-forge,defaults
43 | channel-priority: true
44 | activate-environment: pzero
45 | environment-file: envs/pzero-env-from-history.yml
46 | python-version: 3.11
47 | auto-activate-base: false
48 |
49 | - name: Check Conda Dependencies
50 | run: |
51 | conda info
52 | conda list
53 |
54 | - name: Make executable - Windows
55 | if: ${{ matrix.os == 'windows-latest' }}
56 | run: |
57 | conda activate pzero
58 | pyinstaller pzero-windows.spec
59 | ls
60 |
61 | - name: Make executable - Linux
62 | if: ${{ matrix.os == 'ubuntu-latest' }}
63 | run: |
64 | conda activate pzero
65 | pyinstaller pzero-linux.spec
66 | ls
67 |
68 | - name: Make executable - MacOS
69 | if: ${{ matrix.os == 'macos-latest' }}
70 | run: |
71 | conda activate pzero
72 | pyinstaller pzero-macos.spec
73 | ls
74 |
75 | - name: check path
76 | run: |
77 | cd installers
78 | ls
79 |
80 | - name: Upload Windows Build
81 | if: ${{ matrix.os == 'windows-latest' }}
82 | uses: actions/upload-artifact@v3
83 | with:
84 | name: ${{ matrix.os }} build
85 | path: installers/PZero_Windows/pzero.exe
86 |
87 |
88 | - name: Upload Ubuntu Build
89 | if: ${{ matrix.os == 'ubuntu-latest' }}
90 | uses: actions/upload-artifact@v3
91 | with:
92 | name: ${{ matrix.os }} build
93 | path: installers/PZero_Linux/pzero
94 |
95 |
96 | - name: Upload MacOs Build
97 | if: ${{ matrix.os == 'macos-latest' }}
98 | uses: actions/upload-artifact@v3
99 | with:
100 | name: ${{ matrix.os }} build
101 | path: installers/PZero_Darwin/pzero
--------------------------------------------------------------------------------
/icons/TakeScreenshot.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
93 |
--------------------------------------------------------------------------------
/icons/ResampleNumber.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
84 |
--------------------------------------------------------------------------------
/style/imgs/uparrow2.svg:
--------------------------------------------------------------------------------
1 |
2 |
104 |
--------------------------------------------------------------------------------
/style/imgs/downarrow2.svg:
--------------------------------------------------------------------------------
1 |
2 |
104 |
--------------------------------------------------------------------------------
/style/imgs/leftarrow2.svg:
--------------------------------------------------------------------------------
1 |
2 |
104 |
--------------------------------------------------------------------------------
/icons/SimplifyLine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
61 |
--------------------------------------------------------------------------------
/pzero/imports/stl2vtk.py:
--------------------------------------------------------------------------------
1 | """stl2py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from vtk import vtkSTLWriter
5 |
6 | from pzero.entities_factory import TriSurf
7 |
8 |
9 | def vtk2stl(self=None, out_dir_name=None):
10 | """Exports all triangulated surfaces to a collection of STL surfaces."""
11 | # Create STL writer.
12 | stl_writer = vtkSTLWriter()
13 | stl_writer.SetFileTypeToASCII()
14 | # Loop for each entity.
15 | for uid in self.geol_coll.df["uid"]:
16 | if isinstance(self.geol_coll.get_uid_vtk_obj(uid), TriSurf):
17 | header = (
18 | uid
19 | + "_"
20 | + self.geol_coll.df.loc[self.geol_coll.df["uid"] == uid, "name"].values[
21 | 0
22 | ]
23 | )
24 | out_file_name = (
25 | str(out_dir_name)
26 | + "/"
27 | + uid
28 | + "_"
29 | + self.geol_coll.df.loc[self.geol_coll.df["uid"] == uid, "name"].values[
30 | 0
31 | ]
32 | + ".stl"
33 | )
34 | stl_writer.SetFileName(out_file_name)
35 | vtk_entity = self.geol_coll.get_uid_vtk_obj(uid)
36 | stl_writer.SetInputData(vtk_entity)
37 | stl_writer.SetHeader(header)
38 | stl_writer.Write()
39 | for uid in self.boundary_coll.df["uid"]:
40 | if isinstance(self.boundary_coll.get_uid_vtk_obj(uid), TriSurf):
41 | header = (
42 | uid
43 | + "_"
44 | + self.boundary_coll.df.loc[
45 | self.boundary_coll.df["uid"] == uid, "name"
46 | ].values[0]
47 | )
48 | out_file_name = (
49 | str(out_dir_name)
50 | + "/"
51 | + uid
52 | + "_"
53 | + self.boundary_coll.df.loc[
54 | self.boundary_coll.df["uid"] == uid, "name"
55 | ].values[0]
56 | + ".stl"
57 | )
58 | stl_writer.SetFileName(out_file_name)
59 | vtk_entity = self.boundary_coll.get_uid_vtk_obj(uid)
60 | stl_writer.SetInputData(vtk_entity)
61 | stl_writer.SetHeader(header)
62 | stl_writer.Write()
63 | print("All TSurfs saved.")
64 |
65 |
66 | def vtk2stl_dilation(self=None, out_dir_name=None, tol=1.0):
67 | """Apply dilation then exports all triangulated surfaces to a collection of STL surfaces."""
68 | # Create STL writer.
69 | stl_writer = vtkSTLWriter()
70 | stl_writer.SetFileTypeToASCII()
71 | # Loop for each entity.
72 | for uid in self.geol_coll.df["uid"]:
73 | if isinstance(self.geol_coll.get_uid_vtk_obj(uid), TriSurf):
74 | header = (
75 | uid
76 | + "_"
77 | + self.geol_coll.df.loc[self.geol_coll.df["uid"] == uid, "name"].values[
78 | 0
79 | ]
80 | )
81 | out_file_name = (
82 | str(out_dir_name)
83 | + "/"
84 | + uid
85 | + "_"
86 | + self.geol_coll.df.loc[self.geol_coll.df["uid"] == uid, "name"].values[
87 | 0
88 | ]
89 | + ".stl"
90 | )
91 | stl_writer.SetFileName(out_file_name)
92 | vtk_entity = self.geol_coll.get_uid_vtk_obj(uid)
93 | vtk_entity_dilated = vtk_entity.boundary_dilation(tol=tol)
94 | try:
95 | stl_writer.SetInputData(vtk_entity_dilated)
96 | stl_writer.SetHeader(header)
97 | stl_writer.Write()
98 | except:
99 | pass
100 | print("All TSurfs saved.")
101 |
--------------------------------------------------------------------------------
/style/imgs/rightarrow2.svg:
--------------------------------------------------------------------------------
1 |
2 |
104 |
--------------------------------------------------------------------------------
/old_tests/test_helpers/test_helper_dialogs.py:
--------------------------------------------------------------------------------
1 | from pzero.helpers.helper_dialogs import progress_dialog
2 | import pytest
3 |
4 | """
5 | def test_option_dialogs(self, qtbot):
6 | title = "test_dialog"
7 | message = "this is a test message"
8 | res = options_dialog(title=title, message=message, yes_role="yes", no_role="no")
9 |
10 | qtbot.mouseClick()
11 |
12 | # if pressed no res == 1, otherwise res == 0
13 | assert res == 1
14 | """
15 |
16 |
17 | # Testing the class progress_dialog()
18 | class TestProgressDialog:
19 |
20 | # testing if the initial dialog values are correct
21 | @pytest.fixture
22 | def test_init_dialog(self, qtbot):
23 | max_value = 1
24 | title = "Title_test"
25 | label = "Saving test"
26 |
27 | progress_dialog_instance = progress_dialog(
28 | max_value=max_value,
29 | title_txt=title,
30 | label_txt=label,
31 | cancel_txt=None,
32 | parent=self,
33 | )
34 |
35 | assert (
36 | progress_dialog_instance.value() == -1
37 | and progress_dialog_instance.maximum() == max_value
38 | and progress_dialog_instance.windowTitle() == title
39 | and progress_dialog_instance.labelText() == label
40 | )
41 |
42 | # Testing the add_one function
43 | @pytest.fixture
44 | def test_add_one(self, qtbot):
45 | max_value = 5000
46 | title = "Title_test"
47 | label = "Saving test"
48 |
49 | progress_dialog_instance = progress_dialog(
50 | max_value=max_value,
51 | title_txt=title,
52 | label_txt=label,
53 | cancel_txt=None,
54 | parent=self,
55 | )
56 |
57 | for i in range(max_value):
58 | progress_dialog_instance.add_one()
59 |
60 | # we use max_value -1 because the value in the dialog starts with -1
61 | assert progress_dialog_instance.value() == max_value - 1
62 |
63 | # Testing was_canceled in the progress dialog
64 | @pytest.fixture
65 | def test_was_canceled(self, qtbot):
66 | max_value = 1
67 | title = "Title_test"
68 | label = "Saving test"
69 | cancel_button_text = "test delete me"
70 |
71 | progress_dialog_instance = progress_dialog(
72 | max_value=max_value,
73 | title_txt=title,
74 | label_txt=label,
75 | cancel_txt=cancel_button_text,
76 | parent=self,
77 | )
78 |
79 | assert progress_dialog_instance.wasCanceled() is False
80 |
81 | # Testing with calling the cancel button in the progress dialog
82 | @pytest.fixture
83 | def test_was_canceled_true(self, qtbot):
84 | max_value = 1
85 | title = "Title_test"
86 | label = "Saving test"
87 | cancel_button_text = "test delete me"
88 |
89 | progress_dialog_instance = progress_dialog(
90 | max_value=max_value,
91 | title_txt=title,
92 | label_txt=label,
93 | cancel_txt=cancel_button_text,
94 | parent=self,
95 | )
96 | progress_dialog_instance.cancel()
97 |
98 | assert progress_dialog_instance.wasCanceled() is True
99 |
100 | # Testing change in the dialog
101 | @pytest.fixture
102 | def test_change_dialog_label(self, qtbot):
103 | max_value = 5000
104 | title = "Title_test"
105 | label = "Saving test"
106 | change_label = "new_test_label"
107 |
108 | progress_dialog_instance = progress_dialog(
109 | max_value=max_value,
110 | title_txt=title,
111 | label_txt=label,
112 | cancel_txt=None,
113 | parent=self,
114 | )
115 | progress_dialog_instance.setLabelText(change_label)
116 |
117 | assert progress_dialog_instance.labelText() == change_label
118 |
--------------------------------------------------------------------------------
/icons/CopyKink.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
76 |
--------------------------------------------------------------------------------
/pzero/collections/dom_collection.py:
--------------------------------------------------------------------------------
1 | """dom_collection.py
2 | PZero© Andrea Bistacchi"""
3 |
4 | from .DIM_collection import DIMCollection
5 |
6 |
7 | class DomCollection(DIMCollection):
8 | """Collection for all DOM entities and their metadata."""
9 |
10 | def __init__(self, parent=None, *args, **kwargs):
11 | super(DomCollection, self).__init__(parent, *args, **kwargs)
12 | # Initialize properties required by the abstract superclass.
13 | self.entity_dict = {
14 | "uid": "",
15 | "name": "undef",
16 | "scenario": "undef",
17 | "parent_uid": "", # this is the uid of the cross section for "XsVertexSet", "XsPolyLine", and "XsImage", empty for all others
18 | "textures": [],
19 | "topology": "undef",
20 | "vtk_obj": None,
21 | "properties_names": [],
22 | "properties_components": [],
23 | }
24 |
25 | self.entity_dict_types = {
26 | "uid": str,
27 | "name": str,
28 | "scenario": str,
29 | "parent_uid": str,
30 | "textures": str,
31 | "topology": str,
32 | "vtk_obj": object,
33 | "properties_names": list,
34 | "properties_components": list,
35 | }
36 |
37 | self.valid_topologies = ["DEM", "TSDom", "PCDom"]
38 |
39 | self.collection_name = "dom_coll"
40 |
41 | self.default_colormap = "terrain"
42 |
43 | self.initialize_df()
44 |
45 | # =================================== Obligatory methods ===========================================
46 |
47 | def get_uid_legend(self, uid: str = None) -> dict:
48 | """Get legend for a particular uid."""
49 | legend_dict = self.parent.others_legend_df.loc[
50 | self.parent.others_legend_df["other_collection"] == "DOM"
51 | ].to_dict("records")
52 | return legend_dict[0]
53 |
54 | # =================================== Additional methods ===========================================
55 |
56 | def get_uid_textures(self, uid=None):
57 | """Get value(s) stored in dataframe (as pointer) from uid."""
58 | return self.df.loc[self.df["uid"] == uid, "textures"].values[0]
59 |
60 | def set_uid_textures(self, uid=None, textures=None):
61 | """Set value(s) stored in dataframe (as pointer) from uid.."""
62 | self.df.loc[self.df["uid"] == uid, "textures"] = textures
63 |
64 | def add_map_texture_to_dom(self, dom_uid=None, map_image_uid=None):
65 | """Add a map texture to a DOM."""
66 | row = self.df[self.df["uid"] == dom_uid].index.values[0]
67 | if map_image_uid not in self.df.at[row, "textures"]:
68 | self.get_uid_vtk_obj(dom_uid).add_texture(
69 | map_image=self.parent.image_coll.get_uid_vtk_obj(map_image_uid),
70 | map_image_uid=map_image_uid,
71 | )
72 | self.df.at[row, "textures"].append(map_image_uid)
73 | self.parent.signals.metadata_modified.emit([dom_uid], self)
74 |
75 | def remove_map_texture_from_dom(self, dom_uid=None, map_image_uid=None):
76 | """Remove a map texture from a DOM."""
77 | row = self.df[self.df["uid"] == dom_uid].index.values[0]
78 | if map_image_uid in self.df.at[row, "textures"]:
79 | self.get_uid_vtk_obj(dom_uid).remove_texture(map_image_uid=map_image_uid)
80 | self.df.at[row, "textures"].remove(map_image_uid)
81 | self.parent.signals.data_keys_removed.emit([dom_uid], self)
82 | # print("self.parent.signals.data_keys_removed.emit([dom_uid], self)")
83 | # self.parent.signals.metadata_modified.emit([dom_uid], self)
84 | # print("self.parent.signals.metadata_modified.emit([dom_uid], self)")
85 |
86 | def set_active_texture_on_dom(self, dom_uid=None, map_image_uid=None):
87 | """Set active texture on a DOM."""
88 | self.get_uid_vtk_obj(dom_uid).set_active_texture(map_image_uid=map_image_uid)
89 |
--------------------------------------------------------------------------------
/pzero/ui/navigator_window_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | ################################################################################
4 | ## Form generated from reading UI file 'navigator_windowtkAWbV.ui'
5 | ##
6 | ## Created by: Qt User Interface Compiler version 6.7.3
7 | ##
8 | ## WARNING! All changes made in this file will be lost when recompiling UI file!
9 | ################################################################################
10 |
11 | from PySide6.QtCore import (
12 | QCoreApplication,
13 | QDate,
14 | QDateTime,
15 | QLocale,
16 | QMetaObject,
17 | QObject,
18 | QPoint,
19 | QRect,
20 | QSize,
21 | QTime,
22 | QUrl,
23 | Qt,
24 | )
25 | from PySide6.QtGui import (
26 | QBrush,
27 | QColor,
28 | QConicalGradient,
29 | QCursor,
30 | QFont,
31 | QFontDatabase,
32 | QGradient,
33 | QIcon,
34 | QImage,
35 | QKeySequence,
36 | QLinearGradient,
37 | QPainter,
38 | QPalette,
39 | QPixmap,
40 | QRadialGradient,
41 | QTransform,
42 | )
43 | from PySide6.QtWidgets import (
44 | QApplication,
45 | QGridLayout,
46 | QLabel,
47 | QMainWindow,
48 | QPushButton,
49 | QSizePolicy,
50 | QVBoxLayout,
51 | QWidget,
52 | )
53 |
54 |
55 | class Ui_NavWindow(object):
56 | def setupUi(self, NavWindow):
57 | if not NavWindow.objectName():
58 | NavWindow.setObjectName("NavWindow")
59 | NavWindow.resize(540, 95)
60 | NavWindow.setMinimumSize(QSize(540, 90))
61 | NavWindow.setMaximumSize(QSize(562, 95))
62 | self.centralwidget = QWidget(NavWindow)
63 | self.centralwidget.setObjectName("centralwidget")
64 | self.verticalLayout = QVBoxLayout(self.centralwidget)
65 | self.verticalLayout.setObjectName("verticalLayout")
66 | self.NavGrid = QWidget(self.centralwidget)
67 | self.NavGrid.setObjectName("NavGrid")
68 | sizePolicy = QSizePolicy(
69 | QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred
70 | )
71 | sizePolicy.setHorizontalStretch(0)
72 | sizePolicy.setVerticalStretch(0)
73 | sizePolicy.setHeightForWidth(self.NavGrid.sizePolicy().hasHeightForWidth())
74 | self.NavGrid.setSizePolicy(sizePolicy)
75 | self.NavGrid.setMinimumSize(QSize(540, 45))
76 | self.NavGrid.setMaximumSize(QSize(815, 65))
77 | self.gridLayout = QGridLayout(self.NavGrid)
78 | self.gridLayout.setObjectName("gridLayout")
79 | self.ForwardButton = QPushButton(self.NavGrid)
80 | self.ForwardButton.setObjectName("ForwardButton")
81 |
82 | self.gridLayout.addWidget(self.ForwardButton, 0, 2, 1, 1)
83 |
84 | self.BackButton = QPushButton(self.NavGrid)
85 | self.BackButton.setObjectName("BackButton")
86 |
87 | self.gridLayout.addWidget(self.BackButton, 0, 0, 1, 1)
88 |
89 | self.SectionLabel = QLabel(self.NavGrid)
90 | self.SectionLabel.setObjectName("SectionLabel")
91 | self.SectionLabel.setLayoutDirection(Qt.LayoutDirection.LeftToRight)
92 | self.SectionLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
93 |
94 | self.gridLayout.addWidget(self.SectionLabel, 0, 1, 1, 1)
95 |
96 | self.verticalLayout.addWidget(self.NavGrid)
97 |
98 | NavWindow.setCentralWidget(self.centralwidget)
99 |
100 | self.retranslateUi(NavWindow)
101 |
102 | QMetaObject.connectSlotsByName(NavWindow)
103 |
104 | # setupUi
105 |
106 | def retranslateUi(self, NavWindow):
107 | NavWindow.setWindowTitle(
108 | QCoreApplication.translate("NavWindow", "Navigator", None)
109 | )
110 | self.ForwardButton.setText(QCoreApplication.translate("NavWindow", ">>", None))
111 | self.BackButton.setText(QCoreApplication.translate("NavWindow", "<<", None))
112 | self.SectionLabel.setText("")
113 |
114 | # retranslateUi
115 |
--------------------------------------------------------------------------------
/icons/SectionFromAzimuth.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
78 |
--------------------------------------------------------------------------------
/pzero/README.md:
--------------------------------------------------------------------------------
1 | # PZero Core Modules
2 |
3 | This folder contains the core Python modules for the PZero project. These files implement the main logic, data structures, and algorithms used throughout the application.
4 |
5 | ## File Overview
6 |
7 | - `project_window.py`
8 | Main window class for the PZero application, integrating the UI and core logic. Handles project creation, opening, saving, import/export of various geological data formats, entity management, and connections to all main collections and legends. Provides the central hub for user interaction and workflow orchestration.
9 |
10 | - `entities_factory.py`
11 | Defines the main geometric and geological entity classes used throughout the project, including polylines, triangulated surfaces, point clouds, voxets, images, wells, and related data structures. Provides Pythonic wrappers around VTK and PyVista objects, exposing data as NumPy arrays and offering methods for deep copying, property management, and geometric operations. Supports both geological and non-geological objects, and integrates with orientation analysis utilities.
12 |
13 | - `legend_manager.py`
14 | Manages the legend system for geological, fluid, background, well, and other entity collections. Provides utilities for updating the legend widget, handling color, line thickness, point size, opacity, and sequence changes, and synchronizing legend data with the UI and project dataframes. Integrates with PySide6 and pandas for interactive legend editing and visualization.
15 |
16 | - `properties_manager.py`
17 | Manages property colormaps and legends for geological, DOM, mesh3d, and related collections. Provides utilities for updating property colormap tables, synchronizing with project data, and handling user interactions for property visualization. Integrates with PySide6, matplotlib, colorcet, cmocean, and PyVista for colormap management and display.
18 |
19 | - `two_d_lines.py`
20 | Functions and tools for creating, editing, and manipulating 2D lines, including digitizing, editing, splitting, merging, snapping, and resampling lines. Integrates with the application's map and cross-section views.
21 |
22 | - `three_d_surfaces.py`
23 | Tools and algorithms for creating, editing, and processing 3D surfaces and meshes. Includes Delaunay triangulation, Poisson surface reconstruction, implicit modeling with LoopStructural, surface smoothing, mesh decimation, subdivision, intersection, projection, and retopology. Integrates with VTK, PyVista, and LoopStructural libraries.
24 |
25 | - `point_clouds.py`
26 | Functions and tools for processing, segmenting, and analyzing point cloud data. Includes utilities for normal calculation, region extraction, segmentation by dip and dip direction, decimation, cutting, calibration, and conversion to geological features. Integrates with VTK, PyVista, matplotlib, seaborn, and NumPy for advanced point cloud operations and visualization.
27 |
28 | - `orientation_analysis.py`
29 | Functions for orientation analysis, including conversions between geological orientation measurements (strike, dip, dip direction, plunge, trend), calculation of normal and lineation vectors, and utilities for setting normals on geological entities and point clouds. Integrates with NumPy and project-specific entity classes.
30 |
31 | ## Sub-modules
32 |
33 | - `collections/`
34 | Manages grouped data structures and collections of geological entities, such as layers, surfaces, wells, and other domain-specific objects.
35 |
36 | - `helpers/`
37 | Utility modules for dialogs, widgets, and general helper functions used across the application.
38 |
39 | - `imports/`
40 | Modules and utilities for importing, parsing, and converting external geological data formats into the application's internal structures.
41 |
42 | - `processing/`
43 | Implements core data processing algorithms, computational routines, and utilities for geological modeling, mesh operations, and advanced analysis.
44 |
45 | - `ui/`
46 | Contains user interface components, custom widgets, dialogs, and Qt Designer `.ui` files used to build the application's graphical interface.
47 |
48 | - `views/`
49 | Contains the main view classes for the application's GUI, including map and cross-section windows.
50 |
--------------------------------------------------------------------------------
/pzero/imports/README.md:
--------------------------------------------------------------------------------
1 | # Imports
2 |
3 | This folder contains modules for importing, exporting, and converting various data formats (such as well data, mesh data, images, triangulated surfaces, GIS shapefiles, seismic SEG-Y volumes, PyVista-supported formats, PLY surfaces, point clouds, OBJ surfaces, LandXML surfaces, glTF/GLB models, GOCAD ASCII files, DXF files, DEM rasters, Cesium 3D Tiles, and abstract base classes) into VTK objects and internal representations for the PZero project.
4 |
5 | ## File Overview
6 |
7 | - `well2vtk.py`
8 | Converts well data from Excel and other formats into VTK objects and PZero entities.
9 | **Main function:**
10 | - `well2vtk(self, path=None)`
11 |
12 | - `mesh2vtk.py`
13 | Imports mesh data (e.g., from GOCAD or other sources) and converts them into VTK mesh objects.
14 |
15 | - `image2vtk.py`
16 | Imports image data and converts them into VTK image objects.
17 |
18 | - `stl2vtk.py`
19 | Exports triangulated surfaces (TSurfs) to STL files, with optional boundary dilation.
20 | **Main functions:**
21 | - `vtk2stl(self, out_dir_name)`
22 | - `vtk2stl_dilation(self, out_dir_name, tol=1.0)`
23 |
24 | - `shp2vtk.py`
25 | Imports points and polylines from ESRI Shapefiles (SHP) and other GIS formats.
26 | **Main function:**
27 | - `shp2vtk(self, in_file_name, collection)`
28 |
29 | - `segy2vtk.py`
30 | Imports seismic SEG-Y volumes and converts them into VTK structured grids.
31 | **Main functions:**
32 | - `segy2vtk(self, in_file_name)`
33 | - `read_segy_file(in_file_name)`
34 |
35 | - `pyvista2vtk.py`
36 | Imports various file formats supported by PyVista and adds them as VTK polydata entities.
37 | **Main function:**
38 | - `pyvista2vtk(self)`
39 |
40 | - `ply2vtk.py`
41 | Exports all triangulated surfaces (TSurfs) to PLY files with color information.
42 | **Main function:**
43 | - `vtk2ply(self, out_dir_name)`
44 |
45 | - `pc2vtk.py`
46 | Imports point cloud data from PLY, LAS/LAZ, or CSV files and converts them into VTK point cloud objects.
47 | **Main function:**
48 | - `pc2vtk(in_file_name, col_names, row_range, header_row, usecols, delimiter, self=None)`
49 |
50 | - `obj2vtk.py`
51 | Exports all triangulated surfaces (TSurfs) to OBJ files.
52 | **Main function:**
53 | - `vtk2obj(self, out_dir_name)`
54 |
55 | - `lxml2vtk.py`
56 | Exports triangulated surfaces (TSurfs) to LandXML files and provides a placeholder for LandXML import.
57 | **Main functions:**
58 | - `vtk2lxml(self, out_dir_name=None)`
59 | - `lxml2vtk(self, input_path=None)`
60 |
61 | - `gltf2vtk.py`
62 | Exports all triangulated surfaces (TSurfs) to a GLTF binary file (.glb) using VTK’s GLTF writer.
63 | **Main function:**
64 | - `vtk2gltf(self, out_dir_name=None)`
65 |
66 | - `gocad2vtk.py`
67 | Imports and exports GOCAD ASCII files (VSet, PLine, TSurf) as VTK entities for geology, cross-sections, and boundaries.
68 | **Main functions:**
69 | - `gocad2vtk(self, in_file_name, uid_from_name=None)`
70 | - `gocad2vtk_section(self, in_file_name, ...)`
71 | - `gocad2vtk_boundary(self, in_file_name, uid_from_name=None)`
72 | - `vtk2gocad(self, out_file_name)`
73 |
74 | - `dxf2vtk.py`
75 | Exports all triangulated surfaces, boundaries, and wells to DXF files as 3DFACE objects and 3D polylines, including CSV exports of coordinates.
76 | **Main function:**
77 | - `vtk2dxf(self, out_dir_name=None)`
78 |
79 | - `dem2vtk.py`
80 | Imports Digital Elevation Model (DEM) raster files (e.g., GeoTIFF) and adds them as VTK structured grids to the project.
81 | **Main function:**
82 | - `dem2vtk(self, in_file_name, collection)`
83 |
84 | - `cesium2vtk.py`
85 | Exports all triangulated surfaces to a Cesium 3D Tiles collection (GLTF binary surfaces, .glb) using VTK’s Cesium3DTilesWriter.
86 | **Main function:**
87 | - `vtk2cesium(self, out_dir_name=None)`
88 |
89 | - `AbstractImporter.py`
90 | In theory should provide abstract base classes for import/export operations, ensuring a consistent interface for all importers and exporters, but this is not yet implemented.
91 | **Main class:**
92 | - `BaseIO`: Abstract base class with `import_from_file()` and `output_to_file()` methods to be implemented by subclasses.
93 |
--------------------------------------------------------------------------------
/icons/CleanIntersections.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
51 |
--------------------------------------------------------------------------------