OpenStructure
__init__.py
Go to the documentation of this file.
1 #------------------------------------------------------------------------------
2 # This file is part of the OpenStructure project <www.openstructure.org>
3 #
4 # Copyright (C) 2008-2020 by the OpenStructure authors
5 #
6 # This library is free software; you can redistribute it and/or modify it under
7 # the terms of the GNU Lesser General Public License as published by the Free
8 # Software Foundation; either version 3.0 of the License, or (at your option)
9 # any later version.
10 # This library is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 # details.
14 #
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with this library; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #------------------------------------------------------------------------------
19 from ._ost_gfx import *
20 from .py_gfx_obj import PyGfxObj
21 import functools
22 
23 WHITE=RGB(1.0,1.0,1.0)
24 BLACK=RGB(0.0,0.0,0.0)
25 GREY=RGB(0.5,0.5,0.5)
26 RED=RGB(1.0,0.0,0.0)
27 DARKRED=RGB(0.5,0.0,0.0)
28 LIGHTRED=RGB(1.0,0.5,0.5)
29 GREEN=RGB(0.0,1.0,0.0)
30 DARKGREEN=RGB(0.0,0.5,0.0)
31 LIGHTGREEN=RGB(0.5,1.0,0.5)
32 BLUE=RGB(0.0,0.0,1.0)
33 DARKBLUE=RGB(0.0,0.0,0.5)
34 LIGHTBLUE=RGB(0.5,0.5,1.0)
35 YELLOW=RGB(1.0,1.0,0.0)
36 DARKYELLOW=RGB(0.5,0.5,0.0)
37 LIGHTYELLOW=RGB(1.0,1.0,0.5)
38 CYAN=RGB(0.0,1.0,1.0)
39 DARKCYAN=RGB(0.0,0.5,0.5)
40 LIGHTCYAN=RGB(0.5,1.0,1.0)
41 MAGENTA=RGB(1.0,0.0,1.0)
42 DARKMAGENTA=RGB(0.5,0.0,0.5)
43 LIGHTMAGENTA=RGB(1.0,0.5,1.0)
44 PURPLE=MAGENTA
45 DARKPURPLE=DARKMAGENTA
46 LIGHTPURPLE=LIGHTMAGENTA
47 ORANGE=RGB(1.0,0.5,0.0)
48 DARKORANGE=RGB(0.5,0.25,0.0)
49 LIGHTORANGE=RGB(1.0,0.75,0.5)
50 
51 def Stereo(mode,flip=None,alg=None):
52  """
53  Stereo control
54 
55  :param mode: 0=off, 1=quad-buffered, 2=interlaced
56  :type mode: int
57  :param flip: invert order of left/right display
58  :type flip: bool
59  :param alg: stereo algorithm (0 or 1)
60  :type param: int
61  """
62  if(flip):
63  Scene().SetStereoFlip(flip)
64  if(alg):
65  Scene().SetStereoAlg(alg)
66 
67  Scene().SetStereoMode(mode)
68 
69 def FitToScreen(gfx_ent, width=None, height=None, margin=0.05):
70  """
71  Setup camera such that it is centered on the graphical entity and the entity
72  fits the entire viewport. The longest axes of the entity are aligned along
73  the x- and y- axes of the screen.
74 
75  :param gfx_ent: The graphical entity
76  :type gfx_ent: str or :class:`Entity`
77 
78 
79  """
80  from ost import geom
81  import math
82  def _XYZ(view, axes):
83  """
84  returns the vectors in x, y and z direction respectively. The smallest
85  vector is in z, then y, and the largest along x.
86  """
87  rows=[axes.GetRow(i) for i in range(3)]
88  lengths=[]
89  for axe in rows:
90  min_proj=geom.Dot(axe, view.atoms[0].pos)
91  max_proj=min_proj
92  for atom in view.atoms[1:]:
93  proj=geom.Dot(axe, atom.pos)
94  min_proj=min(proj, min_proj)
95  max_proj=max(proj, max_proj)
96  lengths.append(max_proj-min_proj)
97  def cmp_x(rhs, lhs):
98  # replaced cmp when porting to Python 3
99  #return cmp(lhs[1], rhs[1])
100  return (lhs[1] > rhs[1]) - (lhs[1] < rhs[1])
101  sorted_axes=sorted(zip(rows, lengths), key=functools.cmp_to_key(cmp_x))
102  return [r*l for r,l in sorted_axes]
103  scene=Scene()
104  if not isinstance(gfx_ent, Entity):
105  gfx_ent=scene[str(gfx_ent)]
106  width=width and width or scene.viewport.width
107  height=height and height or scene.viewport.height
108  atom_positions=geom.Vec3List([atom.pos for atom in gfx_ent.view.atoms])
109  axes=atom_positions.principal_axes
110  sorted_axes=_XYZ(gfx_ent.view, axes)
111  x_bigger_than_y=geom.Length(sorted_axes[0])>geom.Length(sorted_axes[1])
112  if x_bigger_than_y:
113  if width>height:
114  x_axes=geom.Normalize(sorted_axes[0])
115  y_axes=geom.Normalize(sorted_axes[1])
116  else:
117  x_axes=geom.Normalize(sorted_axes[1])
118  y_axes=geom.Normalize(sorted_axes[0])
119  else:
120  if width>height:
121  x_axes=geom.Normalize(sorted_axes[1])
122  y_axes=geom.Normalize(sorted_axes[0])
123  else:
124  x_axes=geom.Normalize(sorted_axes[0])
125  y_axes=geom.Normalize(sorted_axes[1])
126  z_axes=geom.Normalize(geom.Cross(x_axes, y_axes))
127  rotation=geom.Mat3(x_axes[0], x_axes[1], x_axes[2],
128  y_axes[0], y_axes[1], y_axes[2],
129  z_axes[0], z_axes[1], z_axes[2])
130  rtc=geom.Mat4(rotation)
131 
132  center=gfx_ent.center
133  aspect=float(width)/float(height)
134  factor_y=1.0/math.tan(math.radians(scene.fov))
135  factor_x=factor_y/aspect
136  z_off=geom.Length(sorted_axes[2])*0.5
137  rtc[0,3]=center[0]
138  rtc[1,3]=center[1]
139  rtc[2,3]=center[2]
140  rtc[3,0]=0
141  rtc[3,1]=0
142  rtc[3,2]=-(max(factor_x*(1+margin)*geom.Length(sorted_axes[0]),
143  factor_y*(1+margin)*geom.Length(sorted_axes[1]))+z_off)
144  scene.SetRTC(rtc)
145 
146 
148  def __init__(self, node_list, name):
149  self._node_list_node_list=node_list
150  self._name_name=name
151 
152  def __iter__(self):
153  for node in self._node_list_node_list:
154  yield getattr(node, self._name_name)
155 
156  def __call__(self, *args, **kwargs):
157  for node in self._node_list_node_list:
158  bound_method=getattr(node, self._name_name)
159  bound_method(*args, **kwargs)
160 
161 class GfxNodeListProxy(object):
162  def __init__(self, node_list):
163  self._nodes_nodes=node_list
164 
165  def __getattr__(self, name):
166  if name.startswith('_'):
167  return super(GfxNodeListProxy, self).__getattr__(name)
168  return GfxNodeListAttrProxy(self._nodes_nodes, name)
169 
170  def __setattr__(self, name, value):
171  if name.startswith('_'):
172  super(GfxNodeListProxy, self).__setattr__(name, value)
173  for node in self._nodes_nodes:
174  setattr(node, name, value)
175 
176 def _Match(scene, pattern="*"):
177  import os
178  import fnmatch
179  def _Recurse(path, node, pattern):
180  matches=[]
181  for child in node.children:
182  full_name=os.path.join(path, child.name)
183  if fnmatch.fnmatchcase(full_name, pattern):
184  matches.append(child)
185  matches.extend(_Recurse(full_name, child, pattern))
186  return matches
187  return GfxNodeListProxy(_Recurse("", Scene().root_node, pattern))
188 
189 SceneSingleton.Match=_Match
190 
191 def _to_vec3(p):
192  import ost.geom
193  if isinstance(p,ost.geom.Vec3):
194  return p
195  else:
196  try:
197  return ost.geom.Vec3(p[0],p[1],p[2])
198  except:
199  raise TypeError("expected either a sequence or a geom.Vec3 object")
200 
201 
202 def _primlist_add_point(self,pos,color=None):
203  pos=_to_vec3(pos)
204  if not color:
205  color=WHITE
206  self._add_point(pos,color)
207 
208 def _primlist_add_line(self,pos1,pos2,color1=None,color2=None,color=None):
209  pos1=_to_vec3(pos1)
210  pos2=_to_vec3(pos2)
211  if not color:
212  color=WHITE
213  if not color1:
214  color1=color
215  if not color2:
216  color2=color1
217  self._add_line(pos1,pos2,color1,color2)
218 
219 def _primlist_add_sphere(self,cen,radius=1.0,color=None):
220  pos=_to_vec3(cen)
221  if not color:
222  color=WHITE
223  self._add_sphere(pos,radius,color)
224 
225 def _primlist_add_cyl(self,pos1,pos2,radius1=None,radius2=None,radius=None,color1=None,color2=None,color=None,):
226  pos1=_to_vec3(pos1)
227  pos2=_to_vec3(pos2)
228  if radius is None:
229  radius=1.0
230  if radius1 is None:
231  radius1=radius
232  if radius2 is None:
233  radius2=radius1
234  if not color:
235  color=WHITE
236  if not color1:
237  color1=color
238  if not color2:
239  color2=color1
240  self._add_cyl(pos1,pos2,radius1,radius2,color1,color2)
241 
242 def _primlist_add_text(self,text,pos,color=None,point_size=None):
243  pos=_to_vec3(pos)
244  if not color:
245  color=WHITE
246  if not point_size:
247  point_size=1.0
248  self._add_text(text,pos,color,point_size)
249 
250 PrimList.AddPoint=_primlist_add_point
251 PrimList.AddLine=_primlist_add_line
252 PrimList.AddSphere=_primlist_add_sphere
253 PrimList.AddCyl=_primlist_add_cyl
254 PrimList.AddText=_primlist_add_text
255 
256 # entity reset
257 
258 def _entity_reset(self,*args,**kwargs):
259  import ost.mol as mol
260  eh=None
261  ev=None
262  qr=None
263  qf=None
264  for a in args:
265  if isinstance(a,mol.Query):
266  if qr:
267  raise TypeError("Reset: more than one query string given")
268  qr=a
269  elif isinstance(a,mol.EntityHandle):
270  if eh:
271  raise TypeError("Reset: more than one entity handle given")
272  eh=a
273  elif isinstance(a,mol.EntityView):
274  if ev:
275  raise TypeError("Reset: more than one entity view given")
276  ev=a
277  elif isinstance(a,str):
278  if qr:
279  raise TypeError("Reset: more than one query string given")
280  qr=mol.Query(a)
281  elif isinstance(a,int):
282  if qf:
283  raise TypeError("Reset: more than one QueryFlags given")
284  qf=a
285  else:
286  raise TypeError("Reset: unknown option of type '%s' given"%type(a))
287 
288  for key,val in kwargs.items():
289  if key=="entity":
290  if not isinstance(val,mol.EntityHandle):
291  raise TypeError("Reset: expected mol.EntityHandle for 'entity' option")
292  if eh:
293  raise TypeError("Reset: more than one entity handle given")
294  eh=val
295  elif key=="view":
296  if not isinstance(val,mol.EntityView):
297  raise TypeError("Reset: expected mol.EntityView for 'view' option")
298  if ev:
299  raise TypeError("Reset: more than one entity view given")
300  ev=val
301  elif key=="query":
302  if isinstance(val,mol.Query):
303  pass
304  elif isinstance(val,str):
305  val=mol.Query(val)
306  else:
307  raise TypeError("Reset: expected mol.Query or string for 'query' option")
308  if qr:
309  raise TypeError("Reset: more than one query string given")
310  qr=val
311  elif key=="query_flags":
312  if not isinstance(val,int):
313  raise TypeError("Reset: expected integer for 'query_flags' option")
314  if qf:
315  raise TypeError("Reset: more than one query flags given")
316  qf=val
317  else:
318  raise TypeError("Reset: unknown key '%s'"%key)
319 
320  if eh and ev:
321  raise TypeError("Reset: entity and view are mutually exclusive options")
322 
323  if ev:
324  self._reset4(ev)
325  else:
326  if not eh:
327  eh = self.query_view.entity
328  if not qr:
329  qr = self.query_view.query
330  if not qf:
331  qf = self.query_view.GetFlags()
332  self._reset3(eh,qr,qf)
333 
334 Entity.Reset=_entity_reset
335 
336 def _scene_export(self,*args,**kwargs):
337  """
338  scene.Export(Exporter)
339  scene.Export("file.png")
340  scene.Export("file.png",(width,height),samples=0,transparency=False)
341  deprecated:
342  scene.Export("file.png",width,height,samples=0,transparency=False)
343  scene.Export("file.png",width,height,transparency)
344  """
345  scene=Scene()
346  tp=False
347  sa=0
348  if "tp" in kwargs:
349  tp=int(kwargs["tp"])
350  if "transparency" in kwargs:
351  tp=int(kwargs["transparency"])
352  if "samples" in kwargs:
353  sa=int(kwargs["samples"])
354 
355  if len(args)==1:
356  if isinstance(args[0],Exporter):
357  scene._export_via_exporter(args[0])
358  return
359  elif type(args[0])==type(""):
360  scene._export_screen(args[0],tp)
361  return
362  elif len(args)==2:
363  if type(args[0]==type("")):
364  # assume second argument is a dimension
365  width=int(args[1][0])
366  height=int(args[1][1])
367  scene._export_buffer(args[0],width,height,sa,tp)
368  return
369  elif len(args)==3:
370  if type(args[0]==type("")):
371  width=int(args[1])
372  height=int(args[2])
373  scene._export_buffer(args[0],width,height,sa,tp)
374  return
375  elif len(args)==4:
376  if type(args[0]==type("")):
377  width=int(args[1])
378  height=int(args[2])
379  tp=int(args[3])
380  scene._export_buffer(args[0],width,height,sa,tp)
381  return
382  # getting here indicates an error
383  raise RuntimeError("""invalid arguments to scene.Export; expected one of
384  Export(gfx.Exporter)
385  Export('file.png')
386  Export('file.png',(width,height),samples=0, transparency=False)
387  Export('file.png',width,height,samples=0, transparency=False) -> deprecated
388  Export('file.png',width,height,transparency) -> deprecated
389  """)
390 
391 SceneSingleton.Export=_scene_export
392 
393 import __main__ as main_mod
394 main_mod.scene=Scene()
395 main_mod.scene.Stereo=Stereo
396 
397 import ost as ost_mod
398 ost_mod.scene=Scene()
399 ost_mod.scene.Stereo=Stereo
400 
401 def GostExporter(file,scale=1.0,to_origin=True):
402  e=GostExporter_(file)
403  e.scale=scale
404  e.to_origin=to_origin
405  return e
406 
407 def ColladaExporter(file,scale=1.0,to_origin=True):
408  e=ColladaExporter_(file)
409  e.scale=scale
410  e.to_origin=to_origin
411  return e
412 
413 def _go_get_vis(go):
414  return go.IsVisible()
415 
416 def _go_set_vis(go,flag):
417  if flag:
418  go.Show()
419  else:
420  go.Hide()
421 
422 GfxObj.visible=property(_go_get_vis,_go_set_vis)
423 
424 
def __init__(self, node_list, name)
Definition: __init__.py:148
def __call__(self, *args, **kwargs)
Definition: __init__.py:156
def __getattr__(self, name)
Definition: __init__.py:165
def __init__(self, node_list)
Definition: __init__.py:162
def __setattr__(self, name, value)
Definition: __init__.py:170
main class for organization and root for the graphical display
Definition: scene.hh:80
Protein or molecule.
definition of EntityView
Definition: entity_view.hh:86
Selection Query.
Definition: query.hh:74
Vec3 Cross(const Vec3 &v1, const Vec3 &v2)
vector cross product
Definition: vecmat3_op.hh:85
Quat DLLEXPORT_OST_GEOM Normalize(const Quat &q)
Real DLLEXPORT_OST_GEOM Dot(const Quat &q0, const Quat &q1)
Real Length(const Vec2 &v)
returns length of vector
Definition: vecmat2_op.hh:41
def FitToScreen(gfx_ent, width=None, height=None, margin=0.05)
Definition: __init__.py:69
Color DLLEXPORT_OST_GFX RGB(float r, float g, float b)
RGB color spec from floats (0.0-1.0)
def ColladaExporter(file, scale=1.0, to_origin=True)
Definition: __init__.py:407
def GostExporter(file, scale=1.0, to_origin=True)
Definition: __init__.py:401