Skip to content

Commit

Permalink
Specify color ramp for volume state
Browse files Browse the repository at this point in the history
Fixes #289
  • Loading branch information
JarrettSJohnson committed Jul 20, 2023
1 parent b034d5c commit 9333da4
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 38 deletions.
35 changes: 22 additions & 13 deletions layer2/ObjectVolume.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<ObjectVolumeState*>(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<float>&& ramp_list)
pymol::Result<> ObjectVolumeSetRamp(ObjectVolume* I, std::vector<float>&& 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<ObjectVolumeState*>(I->getObjectState(state));
if (!ovs) {
return pymol::make_error("Invalid volume state.");
}

ovs->Ramp = std::move(ramp_list);
Expand Down
7 changes: 5 additions & 2 deletions layer2/ObjectVolume.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<float>&& ramp_list);
PyObject* ObjectVolumeGetRamp(ObjectVolume* I, int state);
pymol::Result<> ObjectVolumeSetRamp(ObjectVolume* I, std::vector<float>&& ramp_list, int state);

ObjectMapState * ObjectVolumeGetMapState(ObjectVolume * I);

Expand Down
20 changes: 9 additions & 11 deletions layer3/Executive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<ObjectVolume>(G, objName)) {
result = ObjectVolumeGetRamp(obj, state);
}

PRINTFD(G, FB_Executive) "Executive-GetVolumeRamp Exited.\n" ENDFD;
Expand All @@ -4601,11 +4599,11 @@ PyObject* ExecutiveGetVolumeRamp(PyMOLGlobals * G, const char * objName) {
#endif
}

pymol::Result<> ExecutiveSetVolumeRamp(PyMOLGlobals * G, const char * objName, std::vector<float> ramp_list) {

pymol::Result<> ExecutiveSetVolumeRamp(PyMOLGlobals* G, const char* objName, std::vector<float> ramp_list, int state)
{
auto obj = ExecutiveFindObject<ObjectVolume>(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");
Expand Down
4 changes: 2 additions & 2 deletions layer3/Executive.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<float> ramp_list);
PyObject *ExecutiveGetVolumeRamp(PyMOLGlobals * G, const char * objName);
pymol::Result<> ExecutiveSetVolumeRamp(PyMOLGlobals* G, const char* objName, std::vector<float> ramp_list, int state);
PyObject* ExecutiveGetVolumeRamp(PyMOLGlobals* G, const char* objName, int state);

pymol::Result<std::vector<float>>
ExecutiveGetHistogram(PyMOLGlobals * G, const char * objName, int n_points,
Expand Down
10 changes: 6 additions & 4 deletions layer4/Cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}

Expand All @@ -843,8 +844,9 @@ static PyObject * CmdSetVolumeRamp(PyObject * self, PyObject * args)
char* objName;
PyObject *ramp_list;
std::vector<float> 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)) {
Expand All @@ -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);
}
Expand Down
20 changes: 15 additions & 5 deletions modules/pymol/colorramping.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
'''

import sys
from pymol.constants import CURRENT_STATE

cmd = sys.modules["pymol.cmd"]

_volume_windows = {}
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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
Expand All @@ -135,15 +145,15 @@ 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]

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
Expand Down
4 changes: 3 additions & 1 deletion modules/pymol/creating.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit 9333da4

Please sign in to comment.