-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
1,095 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
from pathlib import Path | ||
from collections import namedtuple | ||
|
||
from athena import colorTable | ||
|
||
from PySide2.QtGui import QColor, QVector3D as vec3d | ||
from PySide2.Qt3DCore import Qt3DCore | ||
from PySide2.Qt3DExtras import Qt3DExtras | ||
|
||
Sphere = namedtuple( 'Sphere', 'color, x, y, z, r' ) | ||
Cylinder = namedtuple ( 'Cylinder', 'color, x1, y1, z1, x2, y2, z2, r' ) | ||
# We'll give defaults for r1, r2, and rho, which are optional in a file. | ||
# This isn't perfect because the default for r2 should be r1*4. Parser | ||
# code should watch for the case where r1 is given and r2 is not, and update | ||
# the r2 value appropriately. | ||
Arrow = namedtuple ( 'Arrow', 'color, x1, y1, z1, x2, y2, z2, r1, r2, rho', defaults=[0.1,0.4,0.75] ) | ||
|
||
class OutputDecorations: | ||
def __init__(self, scale_factor): | ||
self.colors = dict() # maps normalized bild strings to QColors | ||
self.current_color = None | ||
self.spheres = list() | ||
self.cylinders = list() | ||
self.arrows = list() | ||
self.scale_factor = scale_factor / 3.2 | ||
|
||
def addColor( self, tokens ): | ||
color_key = ' '.join(tokens) | ||
if color_key not in self.colors: | ||
if color_key in colorTable.colors: | ||
self.colors[color_key] = QColor( *colorTable.colors[color_key] ) | ||
else: | ||
self.colors[color_key] = QColor( *(float(x)*255 for x in tokens) ) | ||
self.current_color = self.colors[color_key] | ||
|
||
def addSphere( self, tokens ): | ||
self.spheres.append( Sphere( self.current_color, *(float(x)*(self.scale_factor) for x in tokens) ) ) | ||
|
||
def addCylinder( self, tokens ): | ||
self.cylinders.append( Cylinder( self.current_color, *(float(x)*(self.scale_factor) for x in tokens) ) ) | ||
|
||
def addArrow( self, tokens ): | ||
self.arrows.append( Arrow( self.current_color, *(float(x)*(self.scale_factor) for x in tokens) ) ) | ||
|
||
def debugSummary( self ): | ||
pattern = 'parsed BILD: {0} unique colors, {1} spheres, {2} cylinders, {3} arrows' +\ | ||
'\n unknown keywords/counts: {4}' +\ | ||
'\n comment lines: {5}' | ||
return pattern.format( len(self.colors), len(self.spheres), len(self.cylinders), len(self.arrows), | ||
self.unknown_keyword_map, len(self.other_line_list) ) | ||
|
||
|
||
def parseBildFile( filename, scale_factor ): | ||
results = OutputDecorations(scale_factor) | ||
with open(filename,'r') as bild: | ||
unknown_keyword_map = dict() | ||
other_line_list = list() | ||
for line in bild: | ||
tokens = line.split() | ||
token0 = tokens[0] | ||
if( token0 == '.arrow' ): | ||
results.addArrow( tokens[1:] ) | ||
elif( token0 == '.color' ): | ||
results.addColor( tokens[1:] ) | ||
elif token0 == '.cylinder': | ||
results.addCylinder( tokens[1:] ) | ||
elif token0 == '.sphere': | ||
results.addSphere( tokens[1:] ) | ||
elif( tokens[0].startswith('.')): | ||
v = unknown_keyword_map.get(tokens[0],0) | ||
unknown_keyword_map[tokens[0]] = v + 1 | ||
else: | ||
other_line_list.append(tokens) | ||
results.unknown_keyword_map = unknown_keyword_map | ||
results.other_line_list = other_line_list | ||
return results |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
# --- UCSF Chimera Copyright --- | ||
# Copyright (c) 2000 Regents of the University of California. | ||
# All rights reserved. This software provided pursuant to a | ||
# license agreement containing restrictions on its disclosure, | ||
# duplication and use. This notice must be embedded in or | ||
# attached to all copies, including partial copies, of the | ||
# software or any revisions or derivations thereof. | ||
# --- UCSF Chimera Copyright --- | ||
# | ||
# $Id: colorTable.py 26655 2009-01-07 22:02:30Z pett $ | ||
|
||
colors = { | ||
"aquamarine": (127, 255, 212), | ||
"black": (0, 0, 0), | ||
"blue": (0, 0, 255), | ||
"brown": (165, 42, 42), | ||
"chartreuse": (127, 255, 0), | ||
"coral": (255, 127, 80), | ||
"cornflower blue": (100, 149, 237), | ||
"cyan": (0, 255, 255), | ||
"dark cyan": (0, 139, 139), | ||
"dark gray": (169, 169, 169), | ||
"dark grey": (169, 169, 169), | ||
"dark green": (0, 100, 0), | ||
"dark khaki": (189, 183, 107), | ||
"dark magenta": (139, 0, 139), | ||
"dark olive green": (85, 107, 47), | ||
"dark red": (139, 0, 0), | ||
"dark slate blue": (72, 61, 139), | ||
"dark slate gray": (47, 79, 79), | ||
"dark slate grey": (47, 79, 79), | ||
"deep pink": (255, 20, 147), | ||
"deep sky blue": (0, 191, 255), | ||
"dim gray": (105, 105, 105), | ||
"dim grey": (105, 105, 105), | ||
"dodger blue": (30, 144, 255), | ||
"firebrick": (178, 34, 34), | ||
"forest green": (34, 139, 34), | ||
"gold": (255, 215, 0), | ||
"goldenrod": (218, 165, 32), | ||
"gray": (190, 190, 190), | ||
"grey": (190, 190, 190), | ||
"green": (0, 255, 0), | ||
"hot pink": (255, 105, 180), | ||
"khaki": (240, 230, 140), | ||
"light blue": (173, 216, 230), | ||
"light gray": (211, 211, 211), | ||
"light grey": (211, 211, 211), | ||
"light green": (144, 238, 144), | ||
"light sea green": (32, 178, 170), | ||
"lime green": (50, 205, 50), | ||
"magenta": (255, 0, 255), | ||
"medium blue": (50, 50, 205), | ||
"medium purple": (147, 112, 219), | ||
"navy blue": (0, 0, 128), | ||
"olive drab": (107, 142, 35), | ||
"orange red": (255, 69, 0), | ||
"orange": (255, 127, 0), | ||
"orchid": (218, 112, 214), | ||
"pink": (255, 192, 203), | ||
"plum": (221, 160, 221), | ||
"purple": (160, 32, 240), | ||
"red": (255, 0, 0), | ||
"rosy brown": (188, 143, 143), | ||
"salmon": (250, 128, 114), | ||
"sandy brown": (244, 164, 96), | ||
"sea green": (46, 139, 87), | ||
"sienna": (160, 82, 45), | ||
"sky blue": (135, 206, 235), | ||
"slate gray": (112, 128, 144), | ||
"slate grey": (112, 128, 144), | ||
"spring green": (0, 255, 127), | ||
"steel blue": (70, 130, 180), | ||
"tan": (210, 180, 140), | ||
"turquoise": (64, 224, 208), | ||
"violet red": (208, 32, 144), | ||
"white": (255, 255, 255), | ||
"yellow": (255, 255, 0), | ||
} | ||
|
||
def getColorByName(name): | ||
# can raise KeyError | ||
import chimera | ||
color = chimera.Color.lookup(name) | ||
if not color: | ||
r, g, b = colors[name] | ||
color = chimera.MaterialColor(r/255.0, g/255.0, b/255.0) | ||
color.save(name) | ||
return color | ||
|
||
def getTkColorByName(name): | ||
# can raise KeyError | ||
import chimera | ||
color = chimera.Color.lookup(name) | ||
if color: | ||
rgb = tuple([int(255 * v + 0.5) for v in color.rgba()[:3]]) | ||
else: | ||
rgb = colors[name] | ||
return "#%02x%02x%02x" % rgb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import numpy as np | ||
|
||
from PySide2.QtGui import QColor, QVector3D as vec3d | ||
from PySide2.QtCore import QByteArray, Qt | ||
from PySide2.Qt3DCore import Qt3DCore | ||
from PySide2.Qt3DRender import Qt3DRender | ||
|
||
from athena.bildparser import Sphere, Cylinder, Arrow | ||
from athena import geom | ||
|
||
|
||
class SphereDecorations(Qt3DCore.QEntity): | ||
|
||
def __init__(self, parent, bildfile): | ||
super().__init__(parent) | ||
spherelist = bildfile.spheres | ||
num_spheres = len(spherelist) | ||
|
||
if num_spheres == 0: return | ||
|
||
total_vertices = num_spheres | ||
vertex_basetype = geom.basetypes.Float | ||
if( total_vertices < 30000 ): | ||
index_basetype = geom.basetypes.UnsignedShort | ||
else: | ||
index_basetype = geom.basetypes.UnsignedInt | ||
|
||
vertex_nparr = np.zeros([total_vertices,7],dtype=geom.basetype_numpy_codes[vertex_basetype]) | ||
|
||
for idx, (color, x, y, z, r) in enumerate(spherelist): | ||
if color is None: color = QColor('white') | ||
vertex_nparr[idx,:] = x, y, z, r, color.redF(), color.greenF(), color.blueF() | ||
|
||
self.geometry = Qt3DRender.QGeometry(self) | ||
|
||
position_attrname = Qt3DRender.QAttribute.defaultPositionAttributeName() | ||
radius_attrname = 'sphereRadius' | ||
color_attrname = Qt3DRender.QAttribute.defaultColorAttributeName() | ||
|
||
attrspecs = [geom.AttrSpec(position_attrname, column=0, numcols=3), | ||
geom.AttrSpec(radius_attrname, column=3, numcols=1), | ||
geom.AttrSpec(color_attrname, column=4, numcols=3)] | ||
|
||
self.vtx_attrs = geom.buildVertexAttrs( self, vertex_nparr, attrspecs ) | ||
for va in self.vtx_attrs: | ||
self.geometry.addAttribute(va) | ||
|
||
# Create qt3d index buffer | ||
index_nparr = np.arange(len(vertex_nparr),dtype=geom.basetype_numpy_codes[index_basetype]) | ||
self.indexAttr = geom.buildIndexAttr( self, index_nparr ) | ||
self.geometry.addAttribute(self.indexAttr) | ||
|
||
self.renderer = Qt3DRender.QGeometryRenderer(parent) | ||
self.renderer.setGeometry(self.geometry) | ||
self.renderer.setPrimitiveType(Qt3DRender.QGeometryRenderer.Points) | ||
|
||
self.addComponent(self.renderer) | ||
|
||
class CylinderDecorations(Qt3DCore.QEntity): | ||
|
||
def __init__(self, parent, bildfile): | ||
super().__init__(parent) | ||
# Draw the arrow bodies as cylinders too | ||
cylinderlist = bildfile.cylinders + [ Cylinder(*x[:8]) for x in bildfile.arrows] | ||
num_cylinders = len(cylinderlist) | ||
|
||
if num_cylinders == 0: return | ||
|
||
total_vertices = 2 * num_cylinders | ||
vertex_basetype = geom.basetypes.Float | ||
if( total_vertices < 30000 ): | ||
index_basetype = geom.basetypes.UnsignedShort | ||
else: | ||
index_basetype = geom.basetypes.UnsignedInt | ||
|
||
vertex_nparr = np.zeros([total_vertices,7],dtype=geom.basetype_numpy_codes[vertex_basetype]) | ||
for idx, (color, x1, y1, z1, x2, y2, z2, r) in enumerate(cylinderlist): | ||
if color is None: color = QColor('white') | ||
vertex_nparr[2*idx,:] = x1, y1, z1, r, color.redF(), color.greenF(), color.blueF() | ||
vertex_nparr[2*idx+1,:] = x2, y2, z2, r, color.redF(), color.greenF(), color.blueF() | ||
|
||
self.geometry = Qt3DRender.QGeometry(self) | ||
|
||
position_attrname = Qt3DRender.QAttribute.defaultPositionAttributeName() | ||
radius_attrname = 'radius' | ||
color_attrname = Qt3DRender.QAttribute.defaultColorAttributeName() | ||
|
||
attrspecs = [geom.AttrSpec(position_attrname, column=0, numcols=3), | ||
geom.AttrSpec(radius_attrname, column=3, numcols=1), | ||
geom.AttrSpec(color_attrname, column=4, numcols=3)] | ||
|
||
self.vtx_attrs = geom.buildVertexAttrs( self, vertex_nparr, attrspecs ) | ||
for va in self.vtx_attrs: | ||
self.geometry.addAttribute(va) | ||
|
||
# Create qt3d index buffer | ||
index_nparr = np.arange(len(vertex_nparr),dtype=geom.basetype_numpy_codes[index_basetype]) | ||
self.indexAttr = geom.buildIndexAttr( self, index_nparr ) | ||
self.geometry.addAttribute(self.indexAttr) | ||
|
||
self.renderer = Qt3DRender.QGeometryRenderer(parent) | ||
self.renderer.setGeometry(self.geometry) | ||
self.renderer.setPrimitiveType(Qt3DRender.QGeometryRenderer.Lines) | ||
|
||
self.addComponent(self.renderer) | ||
|
Oops, something went wrong.