From 9333da43b267b5f0316ed0ca89b90c10dce309e2 Mon Sep 17 00:00:00 2001 From: Jarrett Johnson Date: Thu, 20 Jul 2023 12:07:03 -0400 Subject: [PATCH] Specify color ramp for volume state Fixes #289 --- layer2/ObjectVolume.cpp | 35 ++++++++++++++++++++++------------- layer2/ObjectVolume.h | 7 +++++-- layer3/Executive.cpp | 20 +++++++++----------- layer3/Executive.h | 4 ++-- layer4/Cmd.cpp | 10 ++++++---- modules/pymol/colorramping.py | 20 +++++++++++++++----- modules/pymol/creating.py | 4 +++- 7 files changed, 62 insertions(+), 38 deletions(-) diff --git a/layer2/ObjectVolume.cpp b/layer2/ObjectVolume.cpp index 75c2111d8..8a88ffa78 100644 --- a/layer2/ObjectVolume.cpp +++ b/layer2/ObjectVolume.cpp @@ -64,6 +64,11 @@ static ObjectVolumeState* ObjectVolumeGetActiveState(ObjectVolume* I) return nullptr; } +CObjectState* ObjectVolume::_getObjectState(int state) +{ + return &State[state]; +} + static ObjectMapState * ObjectVolumeStateGetMapState(ObjectVolumeState * vs) { ObjectMap *map = NULL; @@ -1262,30 +1267,34 @@ void ObjectVolumeRecomputeExtent(ObjectVolume * I) /*==============================================================================*/ -PyObject * ObjectVolumeGetRamp(ObjectVolume * I) +PyObject* ObjectVolumeGetRamp(ObjectVolume* I, int state) { /* TODO: Allow for multi-state maps? */ - PyObject * result = NULL; - ObjectVolumeState *ovs; - - if(I && (ovs = ObjectVolumeGetActiveState(I))) { + if (!I) { + return (PConvAutoNone(nullptr)); + } + if (auto ovs = static_cast(I->getObjectState(state))) { if(!ovs->isUpdated) I->update(); - result = PConvFloatArrayToPyList(ovs->Ramp.data(), ovs->Ramp.size()); + return PConvFloatArrayToPyList(ovs->Ramp.data(), ovs->Ramp.size()); } - - return (PConvAutoNone(result)); + return (PConvAutoNone(nullptr)); } /*==============================================================================*/ -pymol::Result<> ObjectVolumeSetRamp(ObjectVolume * I, std::vector&& ramp_list) +pymol::Result<> ObjectVolumeSetRamp(ObjectVolume* I, std::vector&& ramp_list, int state) { /* TODO: Allow for multi-state maps? */ - ObjectVolumeState *ovs = ObjectVolumeGetActiveState(I); - - if(!ovs || ramp_list.empty()) { - return pymol::make_error("ObjectVolumeSetRamp failed."); + if (!I) { + return pymol::make_error("Invalid volume."); + } + if (ramp_list.empty()) { + return pymol::make_error("Empty ramp."); + } + auto ovs = static_cast(I->getObjectState(state)); + if (!ovs) { + return pymol::make_error("Invalid volume state."); } ovs->Ramp = std::move(ramp_list); diff --git a/layer2/ObjectVolume.h b/layer2/ObjectVolume.h index d1eafecc2..67c805aee 100644 --- a/layer2/ObjectVolume.h +++ b/layer2/ObjectVolume.h @@ -64,6 +64,9 @@ struct ObjectVolume : public pymol::CObject { void invalidate(cRep_t rep, cRepInv_t level, int state) override; int getNFrame() const override; pymol::CObject* clone() const override; + +protected: + CObjectState* _getObjectState(int state) override; }; ObjectVolume *ObjectVolumeFromBox(PyMOLGlobals * G, ObjectVolume * obj, ObjectMap * map, @@ -84,8 +87,8 @@ int ObjectVolumeNewFromPyList(PyMOLGlobals * G, PyObject * list, ObjectVolume ** int ObjectVolumeInvalidateMapName(ObjectVolume * I, const char *name, const char * new_name); CField * ObjectVolumeGetField(ObjectVolume* I); -PyObject * ObjectVolumeGetRamp(ObjectVolume* I); -pymol::Result<> ObjectVolumeSetRamp(ObjectVolume* I, std::vector&& ramp_list); +PyObject* ObjectVolumeGetRamp(ObjectVolume* I, int state); +pymol::Result<> ObjectVolumeSetRamp(ObjectVolume* I, std::vector&& ramp_list, int state); ObjectMapState * ObjectVolumeGetMapState(ObjectVolume * I); diff --git a/layer3/Executive.cpp b/layer3/Executive.cpp index 8881439a6..cb1863c64 100644 --- a/layer3/Executive.cpp +++ b/layer3/Executive.cpp @@ -4580,18 +4580,16 @@ ExecutiveGetHistogram(PyMOLGlobals * G, const char * objName, int n_points, floa return pymol::make_error("failed to get map state"); } -PyObject* ExecutiveGetVolumeRamp(PyMOLGlobals * G, const char * objName) { +PyObject* ExecutiveGetVolumeRamp(PyMOLGlobals* G, const char* objName, int state) { #ifdef _PYMOL_NOPY - return NULL; + return nullptr; #else - pymol::CObject *obj; - PyObject* result = NULL; + PyObject* result = nullptr; PRINTFD(G, FB_Executive) "Executive-GetVolumeRamp Entered.\n" ENDFD; - obj = ExecutiveFindObjectByName(G, objName); - if(obj && obj->type==cObjectVolume) { - result = ObjectVolumeGetRamp((ObjectVolume *) obj); + if (auto obj = ExecutiveFindObject(G, objName)) { + result = ObjectVolumeGetRamp(obj, state); } PRINTFD(G, FB_Executive) "Executive-GetVolumeRamp Exited.\n" ENDFD; @@ -4601,11 +4599,11 @@ PyObject* ExecutiveGetVolumeRamp(PyMOLGlobals * G, const char * objName) { #endif } -pymol::Result<> ExecutiveSetVolumeRamp(PyMOLGlobals * G, const char * objName, std::vector ramp_list) { - +pymol::Result<> ExecutiveSetVolumeRamp(PyMOLGlobals* G, const char* objName, std::vector ramp_list, int state) +{ auto obj = ExecutiveFindObject(G, objName); - if(obj) { - return ObjectVolumeSetRamp(obj, std::move(ramp_list)); + if (obj) { + return ObjectVolumeSetRamp(obj, std::move(ramp_list), state); } return pymol::make_error("Object ", objName, " not found"); diff --git a/layer3/Executive.h b/layer3/Executive.h index a3652f176..c98bcb133 100644 --- a/layer3/Executive.h +++ b/layer3/Executive.h @@ -649,8 +649,8 @@ const char *ExecutiveFindBestNameMatch(PyMOLGlobals * G, const char *name); int ExecutiveSetVisFromPyDict(PyMOLGlobals * G, PyObject * dict); PyObject *ExecutiveGetVisAsPyDict(PyMOLGlobals * G); CField *ExecutiveGetVolumeField(PyMOLGlobals * G, const char * objName, int state); -pymol::Result<> ExecutiveSetVolumeRamp(PyMOLGlobals * G, const char * objName, std::vector ramp_list); -PyObject *ExecutiveGetVolumeRamp(PyMOLGlobals * G, const char * objName); +pymol::Result<> ExecutiveSetVolumeRamp(PyMOLGlobals* G, const char* objName, std::vector ramp_list, int state); +PyObject* ExecutiveGetVolumeRamp(PyMOLGlobals* G, const char* objName, int state); pymol::Result> ExecutiveGetHistogram(PyMOLGlobals * G, const char * objName, int n_points, diff --git a/layer4/Cmd.cpp b/layer4/Cmd.cpp index af241ac58..e7c336f76 100644 --- a/layer4/Cmd.cpp +++ b/layer4/Cmd.cpp @@ -818,7 +818,8 @@ static PyObject * CmdGetVolumeRamp(PyObject * self, PyObject * args) PyObject *result = NULL; int ok = false; char* objName; - ok = PyArg_ParseTuple(args, "Os", &self, &objName); + int state; + ok = PyArg_ParseTuple(args, "Osi", &self, &objName, &state); if(ok) { API_SETUP_PYMOL_GLOBALS; @@ -827,7 +828,7 @@ static PyObject * CmdGetVolumeRamp(PyObject * self, PyObject * args) API_HANDLE_ERROR; } if(ok && (ok = APIEnterBlockedNotModal(G))) { - result = ExecutiveGetVolumeRamp(G,objName); + result = ExecutiveGetVolumeRamp(G, objName, state); APIExitBlocked(G); } @@ -843,8 +844,9 @@ static PyObject * CmdSetVolumeRamp(PyObject * self, PyObject * args) char* objName; PyObject *ramp_list; std::vector float_array; + int state; - API_SETUP_ARGS(G, self, args, "OsO", &self, &objName, &ramp_list); + API_SETUP_ARGS(G, self, args, "OsOi", &self, &objName, &ramp_list, &state); if (!PyList_Check(ramp_list) || !PConvFromPyObject(G, ramp_list, float_array)) { @@ -853,7 +855,7 @@ static PyObject * CmdSetVolumeRamp(PyObject * self, PyObject * args) API_ASSERT(APIEnterBlockedNotModal(G)); auto result = - ExecutiveSetVolumeRamp(G, objName, std::move(float_array)); + ExecutiveSetVolumeRamp(G, objName, std::move(float_array), state); APIExitBlocked(G); return APIResult(G, result); } diff --git a/modules/pymol/colorramping.py b/modules/pymol/colorramping.py index 9c8a51220..e617ac1a0 100644 --- a/modules/pymol/colorramping.py +++ b/modules/pymol/colorramping.py @@ -3,6 +3,8 @@ ''' import sys +from pymol.constants import CURRENT_STATE + cmd = sys.modules["pymol.cmd"] _volume_windows = {} @@ -82,17 +84,23 @@ def volume_ramp_new(name, ramp): namedramps[name] = ramp -def get_volume_color(name, quiet=1, _self=cmd): +def get_volume_color(name, state=CURRENT_STATE, quiet=1, _self=cmd): ''' DESCRIPTION Get the volume color ramp of a volume object. + +ARGUMENTS + + name = str: volume object name + + state = int: state of volume ''' quiet = int(quiet) r = _self.DEFAULT_ERROR with _self.lockcm: - r = _self._cmd.get_volume_ramp(_self._COb, name) + r = _self._cmd.get_volume_ramp(_self._COb, name, int(state)-1) if isinstance(r, list): if not quiet: @@ -112,7 +120,7 @@ def get_volume_color(name, quiet=1, _self=cmd): return r -def volume_color(name, ramp='', quiet=1, _guiupdate=True, _self=cmd): +def volume_color(name, ramp='', state=CURRENT_STATE, quiet=1, _guiupdate=True, _self=cmd): ''' DESCRIPTION @@ -126,6 +134,8 @@ def volume_color(name, ramp='', quiet=1, _guiupdate=True, _self=cmd): with (x, color, alpha, ...) or (x, r, g, b, alpha, ...) values. If empty, get the current volume colors. + state = int: state of volume to color + EXAMPLE fetch 1a00, map, type=2fofc @@ -135,7 +145,7 @@ def volume_color(name, ramp='', quiet=1, _guiupdate=True, _self=cmd): quiet = int(quiet) if not ramp: - return get_volume_color(name, quiet, _self) + return get_volume_color(name, state, quiet, _self) if isinstance(ramp, str) and ramp in namedramps: ramp = namedramps[ramp] @@ -143,7 +153,7 @@ def volume_color(name, ramp='', quiet=1, _guiupdate=True, _self=cmd): ramplist = ramp_expand(ramp) with _self.lockcm: - r = cmd._cmd.set_volume_ramp(_self._COb, name, ramplist) + r = cmd._cmd.set_volume_ramp(_self._COb, name, ramplist, int(state)-1) if _guiupdate and name in _volume_windows: from pymol import gui diff --git a/modules/pymol/creating.py b/modules/pymol/creating.py index 37643ccc7..5f8141413 100644 --- a/modules/pymol/creating.py +++ b/modules/pymol/creating.py @@ -593,6 +593,8 @@ def volume(name, map, ramp='', selection='', buffer=0.0, selection = an atom selection about which to display the mesh with an additional "buffer" (if provided). + state = specifies which state to create. + carve = a radius about each atom in the selection for which to include density. If "carve" is not provided, then the whole brick is displayed. @@ -635,7 +637,7 @@ def volume(name, map, ramp='', selection='', buffer=0.0, int(source_state)-1,int(quiet)) if ramp: - _self.volume_color(name, ramp) + _self.volume_color(name, ramp, state) return r