-
Notifications
You must be signed in to change notification settings - Fork 12
/
cellblender_utils.py
197 lines (157 loc) · 6.37 KB
/
cellblender_utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import os
import bpy
import shutil
import sys
import subprocess
def get_tool_shelf():
tool_shelf = None
area = bpy.context.area
for region in area.regions:
if region.type == 'TOOLS':
tool_shelf = region
return tool_shelf
def wrap_long_text(width, text):
lines = []
arr = text.split()
lengthSum = 0
strSum = ""
for var in arr:
lengthSum+=len(var) + 1
if lengthSum <= width:
strSum += " " + var
else:
lines.append(strSum)
lengthSum = 0
strSum = var
# lines.append(" " + arr[len(arr) - 1])
lines.append(strSum)
return lines
def timeline_view_all ( context ):
if bpy.context.screen != None:
for area in bpy.context.screen.areas:
if area != None:
if area.ui_type == 'TIMELINE':
for region in area.regions:
if region.type == 'WINDOW':
ctx = bpy.context.copy()
ctx['area'] = area
ctx['region'] = region
bpy.ops.action.view_all(ctx)
break # It's not clear if this should break or continue ... breaking for now
def project_files_path():
''' Consolidate the creation of the path to the project files'''
filepath = os.path.dirname(bpy.data.filepath)
filepath, dot, blend = bpy.data.filepath.rpartition(os.path.extsep)
filepath = filepath + "_files"
return filepath
def mcell_files_path():
''' Consolidate the creation of the path to the mcell files'''
filepath = project_files_path()
filepath = os.path.join(filepath, "mcell")
return filepath
def preserve_selection_use_operator(operator, new_obj):
""" Preserve current object selection state and use operator.
It is not uncommon for Blender operators to make use of the current
selection. This means you first have to save the current selection state,
deselect everything, select the object you actually want to do the
operation on, execute the operator, deselect that object, and finally
reselect the original selection state. This sounds silly but can be quite
useful. """
object_list = bpy.context.scene.collection.children[0].objects
selected_objs = [obj for obj in object_list if obj.select_get()]
# Deselect everything currently selected, so the operator doesn't act on it
for obj in selected_objs:
obj.select_set(False)
# Select the object we actually want the operator to act on, use it, and
# deselect.
new_obj.select_set(True)
operator()
new_obj.select_set(False)
# It's annoying if operators change things they shouldn't, so let's restore
# the originally select objects.
for obj in selected_objs:
obj.select_set(True)
def check_val_str(val_str, min_val, max_val):
""" Convert val_str to float if possible. Otherwise, generate error. """
status = ""
val = None
try:
val = float(val_str)
if min_val is not None:
if val < min_val:
status = "Invalid value for %s: %s"
if max_val is not None:
if val > max_val:
status = "Invalid value for %s: %s"
except ValueError:
status = "Invalid value for %s: %s"
return (val, status)
def try_to_import(python_path, required_modules):
if (required_modules == None):
return True
import_test = ''
for module in required_modules:
import_test += ('import %s' + os.linesep) % (module)
cmd = [python_path, '-c', import_test]
process = subprocess.Popen(cmd, stderr=subprocess.PIPE)
process.wait()
if (process.poll()):
return False
else:
return True
def get_python_path(required_modules=None, mcell=None):
python_path = None
# Try user assigned python path first. This won't work if we don't have
# bpy.context.scene.mcell
if (mcell and mcell.cellblender_preferences.python_binary_valid and
try_to_import(mcell.cellblender_preferences.python_binary, required_modules)):
python_path = mcell.cellblender_preferences.python_binary
print("Using user specified Python: " + python_path)
# Try to use the built-in version. This will require the bundled miniconda
# version for the matplotlib plotters.
elif (try_to_import(sys.executable, required_modules)):
python_path = sys.executable
print("Using Blender's Python: " + python_path)
# Try python in the user's PATH. This will probably fail on Windows.
elif (try_to_import(shutil.which("python", mode=os.X_OK), required_modules)):
python_path = shutil.which("python", mode=os.X_OK)
print("Using shutil.which Python: " + python_path)
return python_path
def get_mcell_path ( mcell ):
# If MCell path was set by user, use that one. Otherwise, try to use
# bundled version (i.e. <cellblender_path>/bin/mcell). As a last resort,
# try finding MCell in user's path, which will likely fail on Windows.
mcell_path = None
if sys.platform == "win32":
mcell_binary = "mcell.exe"
else:
mcell_binary = "mcell"
bundled_path = os.path.join(os.path.dirname(__file__), "extensions", "mcell", mcell_binary)
if mcell.cellblender_preferences.mcell_binary_valid:
mcell_path = mcell.cellblender_preferences.mcell_binary
elif is_executable(bundled_path):
mcell_path = bundled_path
else:
mcell_path = shutil.which("mcell", mode=os.X_OK)
return mcell_path
def is_executable(binary_path):
"""Checks for nonexistant or non-executable binary file"""
is_exec = False
try:
st = os.stat(binary_path)
if os.path.isfile(binary_path):
if os.access(binary_path, os.X_OK):
is_exec = True
except Exception as err:
is_exec = False
return is_exec
def get_path_to_parent(self_object):
# Return the Blender class path to the parent object with regard to the Blender Property Tree System
path_to_self = "bpy.context.scene." + self_object.path_from_id()
path_to_parent = path_to_self[0:path_to_self.rfind(".")]
return path_to_parent
def get_parent(self_object):
# Return the parent Blender object with regard to the Blender Property Tree System
path_to_parent = get_path_to_parent(self_object)
parent = eval(path_to_parent)
return parent