"""
Geosoft desktop project interface, which provides access to an active and open Geosoft desktop project.
:Classes:
======================== =====================
:class:`Geosoft_project` the geosoft project
======================== =====================
:Constants:
:DOC_TYPE_DATABASE:
:DOC_TYPE_GRID:
:DOC_TYPE_MAP:
:DOC_TYPE_3DV:
:DOC_TYPE_VOXEL:
:DOC_TYPE_VOXI:
:DOC_TYPE_GMS3D:
:DOC_TYPE_GMS2D:
:DOC_TYPE_ALL:
.. seealso:: :mod:`geosoft.gxapi.GXPROJ`, :mod:`geosoft.gxapi.GXEDB`, :mod:`geosoft.gxapi.GXEMAP`
.. note::
Test example:
`geosoft project tests <https://github.com/GeosoftInc/gxpy/blob/master/examples/om-extensions/test_project.py>`_
"""
import os
import geosoft
import geosoft.gxapi as gxapi
from .utility import dict_from_lst
from . import vv as gxvv
__version__ = geosoft.__version__
def _t(s):
return s
DOC_TYPE_DATABASE = "Database"
DOC_TYPE_GRID = "Grid"
DOC_TYPE_MAP = "Map"
DOC_TYPE_3DV = "3DView"
DOC_TYPE_VOXEL = "Voxel"
DOC_TYPE_VOXI = "VoxelInversion"
DOC_TYPE_GMS3D = "GMS3D"
DOC_TYPE_GMS2D = "GMS2D"
DOC_TYPE_ALL = "All"
[docs]class ProjectException(geosoft.GXRuntimeError):
"""
Exceptions from :mod:`geosoft.gxpy.project`.
.. versionadded:: 9.1
"""
pass
[docs]def running_script():
"""
:returns: 1 if running from a script, 0 if running interactively.
.. versionadded:: 9.1
"""
return not gxapi.GXSYS.interactive()
[docs]class Geosoft_project:
"""
Use this class to interact with an open Geosoft project. This singleton class is available only from an
extension running from an open Geosoft project.
"""
def _list_open_docs(self, dtype):
with gxvv.GXvv(None, 'U2048') as docvv:
gxapi.GXPROJ.list_loaded_documents(docvv.gxvv, dtype)
return docvv.list()
def _list_project_docs(self, dtype):
with gxvv.GXvv(None, 'U2048') as docvv:
gxapi.GXPROJ.list_documents(docvv.gxvv, dtype)
return docvv.list()
def _current_doc(self, dtype):
s = gxapi.str_ref()
gxapi.GXPROJ.current_document_of_type(s, dtype)
return s.value
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
pass
def __repr__(self):
return "{}({})".format(self.__class__, self.__dict__)
def __str__(self):
return self.name
[docs] def __init__(self):
s = gxapi.str_ref()
gxapi.GXPROJ.get_name(s)
self.project_file = os.path.normpath(s.value)
self.name = os.path.basename(self.project_file).split('.')[0]
@property
def gid(self):
""" Geosoft ID of the user"""
return(geosoft.gxpy.gx.gx().gid)
@property
def project_databases(self):
"""list of databases in the project"""
return self._list_project_docs(DOC_TYPE_DATABASE)
@property
def project_grids(self):
"""list of grids in the project"""
return self._list_project_docs(DOC_TYPE_GRID)
@property
def project_maps(self):
"""list of maps in the project"""
return self._list_project_docs(DOC_TYPE_MAP)
@property
def project_3dv(self):
"""list of geosoft_3dv (3D views) in the project"""
return self._list_project_docs(DOC_TYPE_3DV)
@property
def project_voxels(self):
"""list of voxels/voxettes in the project"""
return self._list_project_docs(DOC_TYPE_VOXEL)
@property
def project_voxi_models(self):
"""list of VOXI models in the project"""
return self._list_project_docs(DOC_TYPE_VOXI)
@property
def project_gmsys_3d(self):
"""list of GM-SYS 3D models in the project"""
return self._list_project_docs(DOC_TYPE_GMS3D)
@property
def project_gmsys_2d(self):
"""list of GM-SYS 2D models in the project"""
return self._list_project_docs(DOC_TYPE_GMS2D)
@property
def open_databases(self):
"""list of databases open as a database document"""
return self._list_open_docs(DOC_TYPE_DATABASE)
@property
def open_grids(self):
"""list of grids open as a grid document"""
return self._list_open_docs(DOC_TYPE_GRID)
@property
def open_maps(self):
"""list of maps open as a map document"""
return self._list_open_docs(DOC_TYPE_MAP)
@property
def open_3dv(self):
"""list of geosoft_3dv (3d views) open in a 3D viewer"""
return self._list_open_docs(DOC_TYPE_3DV)
@property
def open_voxels(self):
"""list of voxels/voxets open as a document"""
return self._list_open_docs(DOC_TYPE_VOXEL)
@property
def open_voxi_models(self):
"""list of VOXI models open as a document"""
return self._list_open_docs(DOC_TYPE_VOXI)
@property
def open_gmsys_3d(self):
"""list of GM-SYS 3D models open as a document"""
return self._list_open_docs(DOC_TYPE_GMS3D)
@property
def open_gmsys_2d(self):
"""list of GM-SYS 2D models open as a document"""
return self._list_open_docs(DOC_TYPE_GMS2D)
@property
def current_database(self):
"""the open database that has current (or most recent) focus"""
return self._current_doc(DOC_TYPE_DATABASE)
@property
def current_grid(self):
"""the open grid that has current (or most recent) focus"""
return self._current_doc(DOC_TYPE_GRID)
@property
def current_map(self):
"""the open map that has current (or most recent) focus"""
return self._current_doc(DOC_TYPE_MAP)
@property
def current_3dv(self):
"""the open geosoft_3dv that has current (or most recent) focus"""
return self._current_doc(DOC_TYPE_3DV)
@property
def current_voxel(self):
"""the open voxel that has current (or most recent) focus"""
return self._current_doc(DOC_TYPE_VOXEL)
@property
def current_voxi(self):
"""the open VOXI model that has current (or most recent) focus"""
return self._current_doc(DOC_TYPE_VOXI)
@property
def current_gmsys_3d(self):
"""the open GM-SYS 3D model that has current (or most recent) focus"""
return self._current_doc(DOC_TYPE_GMS3D)
@property
def current_gmsys_2d(self):
"""the open GM-SYS 2D model that has current (or most recent) focus"""
return self._current_doc(DOC_TYPE_GMS2D)
@property
def menus(self):
"""
Oasis montaj menu information: (default_menus, loaded_menus, user_menus)
"""
def_menus = gxapi.GXLST.create(512)
loaded_menus = gxapi.GXLST.create(512)
user_menus = gxapi.GXLST.create(512)
gxapi.GXSYS.get_loaded_menus(def_menus, loaded_menus, user_menus)
return list(dict_from_lst(def_menus).keys()), \
list(dict_from_lst(loaded_menus).keys()), \
list(dict_from_lst(user_menus).keys())
[docs] def current_db_state(self):
"""
Return the state of the current database.
:returns: dict of the current database state, {} if there is no current database.
=================== ========================================================
'disp_chan_list' list of displayed channels
'selection' current selection as (line, channel, start_fid, end_fid)
=================== ========================================================
.. versionadded:: 9.2
"""
sdb = {}
if self.current_database:
glst = gxapi.GXLST.create(4096)
edb = gxapi.GXEDB.current_no_activate()
n = edb.disp_chan_lst(glst)
if n > 0:
sdb['disp_chan_list'] = list(dict_from_lst(glst).keys())
else:
sdb['disp_chan_list'] = []
s = gxapi.str_ref()
sch = gxapi.str_ref()
sln = gxapi.str_ref()
sfd = gxapi.str_ref()
edb.get_current_selection(s, sch, sln, sfd)
if sch.value == '[All]':
sch.value = '*'
if sln.value == '[All]':
sln.value = '*'
if sfd.value == '[All]':
fd = ('*', '*')
elif sfd.value == "[None]":
fd = ('', '')
else:
fd = sfd.value.split(' to ')
fd = (fd[0], fd[1])
sdb['selection'] = (sln.value, sch.value, fd[0], fd[1])
return sdb
[docs] def current_map_state(self):
"""
Return the state of the current map.
:returns: dict of the current map state, {} if no current map.
=============== =========================================================
'current_view' name of the current view
'display_area' (min_x, min_y, max_x, max_y) in units of the current view
'3d_view_name' if a 3D view, name of the view
'point' (x, y) of the current selection point
'cursor' (x, y) of the current cursor location
=============== =========================================================
.. versionadded:: 9.2
"""
smap = {}
if self.current_map:
fx = gxapi.float_ref()
fy = gxapi.float_ref()
fx2 = gxapi.float_ref()
fy2 = gxapi.float_ref()
s = gxapi.str_ref()
smap = {}
emap = gxapi.GXEMAP.current_no_activate()
emap.get_current_view(s)
smap['current_view'] = s.value
emap.get_display_area(fx, fy, fx2, fy2)
smap['display_area'] = (fx.value, fy.value, fx2.value, fy2.value)
if emap.is_3d_view():
emap.get_3d_view_name(s)
smap['3d_view'] = s.value
else:
# 2D
emap.get_cur_point(fx, fy)
smap["point"] = (fx.value, fy.value, None)
emap.get_cursor(fx, fy)
smap["cursor"] = (fx.value, fy.value, None)
return smap
[docs]def user_message(title, message):
"""
Display a message to the user
:param title: message box title
:param message: message
.. versionadded:: 9.2
"""
gxapi.GXSYS.display_message(title, message)
def _user_input_gx(kind):
"""Resolve and run the user_input GX"""
gxapi.GXSYS.set_string("USER_INPUT", "TYPE", str(kind))
dir = os.path.split(__file__)[0]
user_input = os.path.join(os.path.join(dir, 'user_input'), 'user_input.gx')
ret = gxapi.GXSYS.run_gx(user_input)
if ret == -1:
gxapi.GXSYS.cancel_()
return ret
[docs]def pause(title='Pause...', cancel=False):
"""
Display a pause dialog, wait for user to press continue or cancel
:param title: The pause dialog title, default is "Pause..."
:param cancel: If True, show a cancel button
:raises: :py:ex:GXCancel if the user cancels the dialog
.. versionadded:: 9.2
"""
gxapi.GXSYS.filter_parm_group("USER_INPUT", 1)
try:
gxapi.GXSYS.set_string("USER_INPUT", "TITLE", str(title))
if not cancel:
_user_input_gx(9)
else:
_user_input_gx(10)
finally:
gxapi.GXSYS.filter_parm_group("USER_INPUT", 0)
[docs]def add_document(doc, type=None, display=True):
"""
Add a document to the project. The document file can be any supported geosoft
document type.
:param doc: file name for the document to open
:param type: one of DOC_TYPE, default will decode the type from the file extension:
=================
DOC_TYPE_DATABASE
DOC_TYPE_GRID
DOC_TYPE_MAP
DOC_TYPE_3DV
DOC_TYPE_VOXEL
DOC_TYPE_VOXI
DOC_TYPE_GMS3D
DOC_TYPE_GMS2D
DOC_TYPE_ALL
=================
:param display: False to prevent opening of the document, though the document will be added
as a document in the project explorer.
.. versionadded:: 9.3
"""
if not type:
ext = os.path.splitext(doc)[1].lower()
if ext == '.grd' or ('(' in ext):
type = DOC_TYPE_GRID
elif ext == '.gdb':
type = DOC_TYPE_DATABASE
elif ext == '.map':
type = DOC_TYPE_MAP
elif ext == '.geosoft_voxel':
type = DOC_TYPE_VOXEL
elif ext == '.geosoft_voxi':
type = DOC_TYPE_VOXI
elif ext == '.geosoft_3dv':
type = DOC_TYPE_3DV
elif ext == '.geosoft_gmsys2d':
type = DOC_TYPE_GMS2D
elif ext == '.geosoft_gmsys3d':
type = DOC_TYPE_GMS3D
else:
raise ProjectException('Cannot determine document type for file extension {}'.format(ext))
gxapi.GXPROJ.add_document(doc, type, display)
[docs]def remove_document(doc):
"""
Remove a document from the project. The document is identified by the document name, which
is either a complete file path name, with qualifiers, or the name of the document in the project storage.
:param doc: document name (file and qualifiers if the document source is a file).
.. versionadded:: 9.3
"""
gxapi.GXPROJ.remove_document(doc)