class Notes(ModelObject): info = ModelObjectInfo("plugins/basic/notes.svg") authors = [authors.toon_verstraelen] # # Properties # def set_notes(self, notes, init=False): self.notes = notes properties = [ Property("notes", StringIO.StringIO(), lambda self: self.notes, set_notes) ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo("Basic", (0, 10), fields.edit.TextView( label_text="Notes", attribute_name="notes", )) ])
class SavedSelection(ReferentBase): info = ModelObjectInfo("plugins/basic/saved_selection.svg", "RestoreSavedSelection") authors = [authors.toon_verstraelen] def set_targets(self, targets, init=False): self.set_children([Reference(prefix="Selected") for target in targets]) ReferentBase.set_targets(self, targets, init)
class ConscanResults(ReferentBase): info = ModelObjectInfo("plugins/builder/conscan_results.svg", "ShowConscanResultsWindow") authors = [authors.toon_verstraelen] # # State # def initnonstate(self): ReferentBase.initnonstate(self) self.set_children( [Reference(prefix="First"), Reference(prefix="Second")]) # # Properties # def get_connections(self): def get_index(node): if node is None: return -1 node = node() if node is None: return -1 if node.model != context.application.model: return -1 return node.get_index() return [(quality, transformation, [ (get_index(node1), get_index(node2)) for node1, node2 in pairs ], [(get_index(node1), get_index(node2)) for node1, node2 in inverse_pairs]) for quality, transformation, pairs, inverse_pairs in self.connections] def set_connections(self, connections, init=False): def get_ref(frame_index, index): if index is -1: return None else: return weakref.ref( self.children[frame_index].target.children[index]) self.connections = [ (quality, transformation, [(get_ref(0, index1), get_ref(1, index2)) for index1, index2 in pairs], [(get_ref(0, index1), get_ref(1, index2)) for index1, index2 in inverse_pairs]) for quality, transformation, pairs, inverse_pairs in connections ] properties = [ Property("connections", [], get_connections, set_connections), ]
class Frame(GLFrameBase, FrameAxes): info = ModelObjectInfo("plugins/basic/frame.svg") authors = [authors.toon_verstraelen] def initnonstate(self): GLFrameBase.initnonstate(self, Complete) # # Tree # @classmethod def check_add(Class, ModelObjectClass): if not GLFrameBase.check_add(ModelObjectClass): return False Universe = context.application.plugins.get_node("Universe") if issubclass(ModelObjectClass, Universe): return False return True # # Draw # def draw(self): FrameAxes.draw(self, self.selected) GLFrameBase.draw(self) # # Revalidation # def revalidate_bounding_box(self): GLFrameBase.revalidate_bounding_box(self) FrameAxes.extend_bounding_box(self, self.bounding_box) # # Signal handlers # def on_select_changed(self, foo): GLFrameBase.on_select_changed(self, foo) self.invalidate_draw_list()
class Point(GLGeometricBase, ColorMixin): info = ModelObjectInfo("plugins/basic/point.svg") authors = [authors.toon_verstraelen] def initnonstate(self): GLGeometricBase.initnonstate(self, Translation) # # Properties # def set_spike_length(self, spike_length, init=False): self.spike_length = spike_length if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() def set_spike_thickness(self, spike_thickness, init=False): self.spike_thickness = spike_thickness if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() properties = [ Property("spike_length", 0.3, lambda self: self.spike_length, set_spike_length), Property("spike_thickness", 0.1, lambda self: self.spike_thickness, set_spike_thickness), ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo( "Geometry", (2, 7), fields.faulty.Length(label_text="Spike length", attribute_name="spike_length", low=0.0, low_inclusive=False)), DialogFieldInfo( "Geometry", (2, 8), fields.faulty.Length(label_text="Spike thickness", attribute_name="spike_thickness", low=0.0, low_inclusive=False)) ]) # # Draw # def draw_spike(self): ColorMixin.draw(self) vb = context.application.vis_backend vb.draw_quad_strip( (numpy.array([0.5773502692, -0.5773502692, -0.5773502692]), [ numpy.array( [self.spike_length, self.spike_length, self.spike_length]) ]), (numpy.array([1, 0, 0 ]), [numpy.array([self.spike_thickness, 0, 0])]), (numpy.array([-0.5773502692, 0.5773502692, -0.5773502692]), [ numpy.array( [self.spike_length, self.spike_length, self.spike_length]) ]), (numpy.array([0, 1, 0 ]), [numpy.array([0, self.spike_thickness, 0])]), (numpy.array([-0.5773502692, -0.5773502692, 0.5773502692]), [ numpy.array( [self.spike_length, self.spike_length, self.spike_length]) ]), (numpy.array([0, 0, 1 ]), [numpy.array([0, 0, self.spike_thickness])]), (numpy.array([0.5773502692, -0.5773502692, -0.5773502692]), [ numpy.array( [self.spike_length, self.spike_length, self.spike_length]) ]), (numpy.array([1, 0, 0 ]), [numpy.array([self.spike_thickness, 0, 0])])) def draw(self): GLGeometricBase.draw(self) vb = context.application.vis_backend vb.push_matrix() for i in range(2): for i in range(4): self.draw_spike() vb.rotate(90, 1.0, 0.0, 0.0) vb.rotate(180, 0.0, 1.0, 0.0) vb.pop_matrix() # # Revalidation # def revalidate_bounding_box(self): GLGeometricBase.revalidate_bounding_box(self) self.bounding_box.extend_with_corners( numpy.array( [[-self.spike_length, -self.spike_length, -self.spike_length], [self.spike_length, self.spike_length, self.spike_length]]))
class Arrow(Vector, ColorMixin): info = ModelObjectInfo("plugins/basic/arrow.svg") authors = [authors.toon_verstraelen] # # Properties # def set_radius(self, radius, init=False): self.radius = radius if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() def set_quality(self, quality, init=False): self.quality = quality if not init: self.invalidate_draw_list() def set_arrow_length(self, arrow_length, init=False): self.arrow_length = arrow_length if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() def set_arrow_radius(self, arrow_radius, init=False): self.arrow_radius = arrow_radius if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() def set_arrow_position(self, arrow_position, init=False): self.arrow_position = arrow_position if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() properties = [ Property("radius", 0.15, lambda self: self.radius, set_radius), Property("quality", 15, lambda self: self.quality, set_quality), Property("arrow_length", 0.6, lambda self: self.arrow_length, set_arrow_length), Property("arrow_radius", 0.3, lambda self: self.arrow_radius, set_arrow_radius), Property("arrow_position", 0.5, lambda self: self.arrow_position, set_arrow_position) ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo( "Geometry", (2, 2), fields.faulty.Length( label_text="Radius", attribute_name="radius", low=0.0, low_inclusive=False, )), DialogFieldInfo( "Geometry", (2, 3), fields.faulty.Length( label_text="Arrow length", attribute_name="arrow_length", low=0.0, )), DialogFieldInfo( "Geometry", (2, 4), fields.faulty.Length( label_text="Arrow radius", attribute_name="arrow_radius", low=0.0, low_inclusive=False, )), DialogFieldInfo( "Geometry", (2, 5), fields.faulty.Float( label_text="Arrow position", attribute_name="arrow_position", low=0.0, high=1.0, )), DialogFieldInfo( "Markup", (1, 3), fields.faulty.Int( label_text="Quality", attribute_name="quality", minimum=3, )), ]) # # Draw # def draw(self): Vector.draw(self) ColorMixin.draw(self) vb = context.application.vis_backend if self.length == 0.0: return # usefull variable if self.arrow_radius <= 0: arrowtop_length = self.arrow_length else: arrowtop_length = self.arrow_length / self.arrow_radius * self.radius # stick and bottom if (self.length - arrowtop_length > 0) and (self.radius > 0): vb.draw_cylinder(self.radius, self.length - arrowtop_length, self.quality) vb.set_quadric_inside() vb.draw_disk(self.radius, self.quality) # arrowtop if (self.radius > 0): if (arrowtop_length > 0): vb.push_matrix() vb.translate(0.0, 0.0, self.length - arrowtop_length) vb.set_quadric_outside() vb.draw_cone(self.radius, 0, arrowtop_length, self.quality) vb.pop_matrix() else: vb.push_matrix() vb.translate(0.0, 0.0, self.length) vb.set_quadric_outside() vb.draw_disk(self.radius, self.quality) vb.pop_matrix() # arrow if (self.arrow_radius - self.radius > 0) and (self.arrow_length - arrowtop_length) > 0: vb.push_matrix() vb.translate(0.0, 0.0, (self.length - self.arrow_length) * (self.arrow_position)) vb.set_quadric_outside() vb.draw_cone(self.arrow_radius, self.radius, self.arrow_length - arrowtop_length, self.quality) vb.set_quadric_inside() vb.draw_disk(self.arrow_radius, self.quality) vb.pop_matrix() vb.set_quadric_outside() # # Revalidation # def revalidate_bounding_box(self): Vector.revalidate_bounding_box(self) if self.length > 0.0: self.bounding_box.extend_with_corners( numpy.array([[0.0, 0.0, 0.0], [0.0, 0.0, self.length]])) temp = { True: self.radius, False: self.arrow_radius }[self.radius > self.arrow_radius] self.bounding_box.extend_with_corners( numpy.array([[-temp, -temp, 0.0], [temp, temp, 0.0]]))
class Plane(GLReferentBase, ColorMixin): info = ModelObjectInfo("plugins/basic/plane.svg") authors = [authors.toon_verstraelen] # # State # def set_targets(self, targets, init=False): self.set_children([SpatialReference("Point") for target in targets]) GLReferentBase.set_targets(self, targets, init) # # Properties # def set_margin(self, margin, init=False): self.margin = margin if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() properties = [ Property("margin", 1.0, lambda self: self.margin, set_margin), ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo( "Geometry", (2, 10), fields.faulty.Length( label_text="Margin", attribute_name="margin", low=0.0, low_inclusive=True, )), ]) # # Draw # def update_normal(self): self.points = numpy.array([ child.target.get_frame_relative_to(self.parent).t for child in self.children if child.target is not None ], float) self.center = sum(self.points) / len(self.points) tmp = self.points - self.center tensor = (tmp.ravel()**2).sum() * numpy.identity(3) - numpy.dot( tmp.transpose(), tmp) evals, evecs = numpy.linalg.eigh(tensor) indices = evals.argsort() self.x = evecs[:, indices[0]] self.y = evecs[:, indices[1]] if numpy.linalg.det(evecs) < 0: self.normal = evecs[:, indices[2]] else: self.normal = -evecs[:, indices[2]] px = numpy.dot(tmp, self.x) py = numpy.dot(tmp, self.y) px_low = px.min() - self.margin px_high = px.max() + self.margin py_low = py.min() - self.margin py_high = py.max() + self.margin self.l_l = self.x * px_low + self.y * py_low + self.center self.l_h = self.x * px_low + self.y * py_high + self.center self.h_l = self.x * px_high + self.y * py_low + self.center self.h_h = self.x * px_high + self.y * py_high + self.center def draw(self): GLReferentBase.draw(self) ColorMixin.draw(self) self.update_normal() vb = context.application.vis_backend vb.draw_quads(( self.normal, [ self.l_l + 0.001 * self.normal, self.l_h + 0.001 * self.normal, self.h_h + 0.001 * self.normal, self.h_l + 0.001 * self.normal, ], ), ( -self.normal, [ self.h_l - 0.001 * self.normal, self.h_h - 0.001 * self.normal, self.l_h - 0.001 * self.normal, self.l_l - 0.001 * self.normal, ], )) # # Revalidation # def revalidate_bounding_box(self): GLReferentBase.revalidate_bounding_box(self) self.update_normal() self.bounding_box.extend_with_point(self.l_l) self.bounding_box.extend_with_point(self.l_h) self.bounding_box.extend_with_point(self.h_l) self.bounding_box.extend_with_point(self.h_h) # # Vector # def define_target(self, reference, new_target): GLReferentBase.define_target(self, reference, new_target) self.invalidate_boundingbox_list() self.invalidate_draw_list() def target_moved(self, reference, target): GLReferentBase.target_moved(self, reference, target) self.invalidate_boundingbox_list() self.invalidate_draw_list()
class Spring(Vector, ColorMixin): info = ModelObjectInfo("plugins/builder/spring.svg") authors = [authors.toon_verstraelen] # # Properties # def set_radius(self, radius, init=False): self.radius = radius if not init: self.invalidate_draw_list() def set_quality(self, quality, init=False): self.quality = quality if not init: self.invalidate_draw_list() def set_rest_length(self, rest_length, init=False): self.rest_length = rest_length if not init: self.invalidate_draw_list() properties = [ Property("radius", 0.5, lambda self: self.radius, set_radius), Property("quality", 15, lambda self: self.quality, set_quality), Property("rest_length", 0.0, lambda self: self.rest_length, set_rest_length), ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo( "Geometry", (2, 2), fields.faulty.Length( label_text="Radius", attribute_name="radius", low=0.0, low_inclusive=False, )), DialogFieldInfo( "Markup", (1, 3), fields.faulty.Int( label_text="Quality", attribute_name="quality", minimum=3, )), DialogFieldInfo( "Basic", (0, 8), fields.faulty.Length( label_text="Rest length", attribute_name="rest_length", low=0.0, low_inclusive=True, )), ]) # # Draw # def draw(self): Vector.draw(self) ColorMixin.draw(self) vb = context.application.vis_backend if self.length > self.rest_length: l_cyl = self.rest_length l_cone = 0.5 * (self.length - l_cyl) if l_cone > 0: vb.draw_cone(self.radius, 0.0, l_cone, self.quality) vb.translate(0.0, 0.0, l_cone) if l_cyl > 0: vb.draw_cone(0.5 * self.radius, 0.5 * self.radius, l_cyl, self.quality) vb.translate(0.0, 0.0, l_cyl) if l_cone > 0: vb.draw_cone(0.0, self.radius, l_cone, self.quality) else: l_cyl = self.length l_cone = 0.5 * (self.rest_length - self.length) if l_cone > 0: vb.translate(0.0, 0.0, -l_cone) vb.draw_cone(0.0, self.radius, l_cone, self.quality) vb.translate(0.0, 0.0, l_cone) if l_cyl > 0: vb.draw_cylinder(0.5 * self.radius, l_cyl, self.quality) vb.translate(0.0, 0.0, l_cyl) if l_cone > 0: vb.draw_cone(self.radius, 0.0, l_cone, self.quality) # # Revalidation # def revalidate_bounding_box(self): Vector.revalidate_bounding_box(self) if self.length > 0: self.bounding_box.extend_with_point( numpy.array([-self.radius, -self.radius, 0])) self.bounding_box.extend_with_point( numpy.array([self.radius, self.radius, self.length]))
class Universe(GLPeriodicContainer, FrameAxes): info = ModelObjectInfo("plugins/basic/universe.svg") authors = [authors.toon_verstraelen] clip_margin = 0.1 # # State # def initnonstate(self): GLPeriodicContainer.initnonstate(self) self.model_center = Translation.identity() def update_center(self): self.model_center = Translation( 0.5 * numpy.dot(self.cell.matrix, self.repetitions * self.cell.active)) # # Properties # def set_cell(self, cell, init=False): GLPeriodicContainer.set_cell(self, cell, init) if not init: self.update_clip_planes() self.update_center() self.invalidate_total_list() self.invalidate_box_list() def set_repetitions(self, repetitions, init=False): self.repetitions = repetitions if not init: self.update_clip_planes() self.update_center() self.invalidate_box_list() self.invalidate_total_list() def set_box_visible(self, box_visible, init=False): self.box_visible = box_visible if not init: self.invalidate_total_list() def set_clipping(self, clipping, init=False): self.clipping = clipping if not init: self.invalidate_total_list() self.invalidate_box_list() self.update_clip_planes() properties = [ Property("repetitions", numpy.array([1, 1, 1], int), lambda self: self.repetitions, set_repetitions), Property("box_visible", True, lambda self: self.box_visible, set_box_visible), Property("clipping", False, lambda self: self.clipping, set_clipping), ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo( "Unit cell", (5, 2), fields.composed.Repetitions( label_text="Repetitions", attribute_name="repetitions", )), DialogFieldInfo( "Markup", (1, 5), fields.edit.CheckButton( label_text="Show periodic box (if active)", attribute_name="box_visible", )), DialogFieldInfo( "Markup", (1, 6), fields.edit.CheckButton( label_text="Clip the unit cell contents.", attribute_name="clipping", )), ]) # # Tree # @classmethod def check_add(Class, ModelObjectClass): if not GLPeriodicContainer.check_add(ModelObjectClass): return False if issubclass(ModelObjectClass, Universe): return False return True # # OpenGL # def initialize_gl(self): vb = context.application.vis_backend self.set_clip_planes() self.update_center() self.box_list = vb.create_list() ##print "Created box list (%i): %s" % (self.box_list, self.get_name()) self.box_list_valid = True GLPeriodicContainer.initialize_gl(self) def cleanup_gl(self): vb = context.application.vis_backend GLPeriodicContainer.cleanup_gl(self) ##print "Deleting box list (%i): %s" % (self.box_list, self.get_name()) vb.delete_list(self.box_list) del self.box_list del self.box_list_valid self.unset_clip_planes() # # Clipping # def update_clip_planes(self): if self.gl_active > 0: self.unset_clip_planes() self.set_clip_planes() def set_clip_planes(self): if not self.clipping: return clip_planes = context.application.scene.clip_planes assert len(clip_planes) == 0 active, inactive = self.cell.active_inactive for index in active: axis = self.cell.matrix[:, index] ortho = self.cell.reciprocal[index] / numpy.linalg.norm( self.cell.reciprocal[index]) length = abs(numpy.dot(ortho, axis)) repetitions = self.repetitions[index] clip_planes.append(numpy.array(list(ortho) + [self.clip_margin])) clip_planes.append( numpy.array( list(-ortho) + [repetitions * length + self.clip_margin])) context.application.main.drawing_area.queue_draw() def unset_clip_planes(self): context.application.scene.clip_planes = [] context.application.main.drawing_area.queue_draw() def shortest_vector(self, delta): return self.cell.shortest_vector(delta) # # Invalidation # def invalidate_box_list(self): if self.gl_active > 0 and self.box_list_valid: self.box_list_valid = False context.application.main.drawing_area.queue_draw() context.application.scene.add_revalidation( self.revalidate_box_list) ##print "EMIT %s: on-box-list-invalidated" % self.get_name() def invalidate_all_lists(self): self.invalidate_box_list() GLPeriodicContainer.invalidate_all_lists(self) # # Draw # def draw_box(self): vb = context.application.vis_backend vb.set_line_width(2) vb.set_specular(False) col = {True: 4.0, False: 2.5}[self.selected] sat = {True: 0.0, False: 0.5}[self.selected] gray = {True: 4.0, False: 2.5}[self.selected] def draw_three(origin): if self.cell.active[0]: vb.set_color(col, sat, sat) vb.draw_line(origin, origin + self.cell.matrix[:, 0]) if self.cell.active[1]: vb.set_color(sat, col, sat) vb.draw_line(origin, origin + self.cell.matrix[:, 1]) if self.cell.active[2]: vb.set_color(sat, sat, col) vb.draw_line(origin, origin + self.cell.matrix[:, 2]) def draw_gray(origin, axis1, axis2, n1, n2, delta, nd): c = context.application.configuration.periodic_box_color vb.set_color(gray * c[0], gray * c[1], gray * c[2], c[3]) if n1 == 0 and n2 == 0: return for i1 in xrange(n1 + 1): if i1 == 0: b2 = 1 vb.draw_line(origin + delta, origin + nd * delta) else: b2 = 0 for i2 in xrange(b2, n2 + 1): vb.draw_line(origin + i1 * axis1 + i2 * axis2, origin + i1 * axis1 + i2 * axis2 + nd * delta) def draw_ortho(origin, axis1, axis2, n1, n2, delta): c = context.application.configuration.periodic_box_color vb.set_color(gray * c[0], gray * c[1], gray * c[2], c[3]) if n1 == 0 and n2 == 0: return for i1 in xrange(n1 + 1): for i2 in xrange(n2 + 1): vb.draw_line( origin + i1 * axis1 + i2 * axis2 - 0.5 * delta, origin + i1 * axis1 + i2 * axis2 + 0.5 * delta) origin = numpy.zeros(3, float) draw_three(origin) repetitions = self.repetitions * self.cell.active if self.cell.active[2]: draw_gray(origin, self.cell.matrix[:, 0], self.cell.matrix[:, 1], repetitions[0], repetitions[1], self.cell.matrix[:, 2], repetitions[2]) else: draw_ortho(origin, self.cell.matrix[:, 0], self.cell.matrix[:, 1], repetitions[0], repetitions[1], self.cell.matrix[:, 2]) if self.cell.active[0]: draw_gray(origin, self.cell.matrix[:, 1], self.cell.matrix[:, 2], repetitions[1], repetitions[2], self.cell.matrix[:, 0], repetitions[0]) else: draw_ortho(origin, self.cell.matrix[:, 1], self.cell.matrix[:, 2], repetitions[1], repetitions[2], self.cell.matrix[:, 0]) if self.cell.active[1]: draw_gray(origin, self.cell.matrix[:, 2], self.cell.matrix[:, 0], repetitions[2], repetitions[0], self.cell.matrix[:, 1], repetitions[1]) else: draw_ortho(origin, self.cell.matrix[:, 2], self.cell.matrix[:, 0], repetitions[2], repetitions[0], self.cell.matrix[:, 1]) vb.set_specular(True) def draw(self): FrameAxes.draw(self, self.selected) GLPeriodicContainer.draw(self) # # Revalidation # def revalidate_box_list(self): if self.gl_active > 0: ##print "Compiling box list (%i): %s" % (self.box_list, self.get_name()) vb = context.application.vis_backend vb.begin_list(self.box_list) if sum(self.cell.active) > 0: self.draw_box() vb.end_list() self.box_list_valid = True def revalidate_total_list(self): if self.gl_active > 0: ##print "Compiling total list (%i): %s" % (self.total_list, self.get_name()) vb = context.application.vis_backend vb.begin_list(self.total_list) if self.visible: vb.push_name(self.draw_list) if sum(self.cell.active) == 0: if self.selected: vb.call_list(self.boundingbox_list) else: if self.selected: vb.set_bright(True) else: vb.set_bright(False) if self.box_visible: vb.call_list(self.box_list) # repeat the draw list for all the unit cell images. if self.clipping: repetitions = (self.repetitions + 2) * self.cell.active + 1 - self.cell.active else: repetitions = self.repetitions * self.cell.active + 1 - self.cell.active for position in iter_all_positions(repetitions): vb.push_matrix() t = numpy.dot( self.cell.matrix, numpy.array(position) - self.cell.active * self.clipping) vb.translate(*t) vb.call_list(self.draw_list) vb.pop_matrix() vb.pop_name() vb.end_list() self.total_list_valid = True def revalidate_bounding_box(self): GLPeriodicContainer.revalidate_bounding_box(self) FrameAxes.extend_bounding_box(self, self.bounding_box) # # Signal handlers # def on_select_chaged(self, selected): GLPeriodicContainer.on_select_chaged(self, selected) self.invalidate_box_list()
class Sphere(GLGeometricBase, ColorMixin): info = ModelObjectInfo("plugins/basic/sphere.svg") authors = [authors.toon_verstraelen] def initnonstate(self): GLGeometricBase.initnonstate(self, Translation) # # Properties # def set_radius(self, radius, init=False): self.radius = radius if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() def set_quality(self, quality, init=False): self.quality = quality if not init: self.invalidate_draw_list() properties = [ Property("radius", 0.5, lambda self: self.radius, set_radius), Property("quality", 15, lambda self: self.quality, set_quality), ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo("Geometry", (2, 2), fields.faulty.Length( label_text="Radius", attribute_name="radius", low=0.0, low_inclusive=False, )), DialogFieldInfo("Markup", (1, 3), fields.faulty.Int( label_text="Quality", attribute_name="quality", minimum=3, )) ]) # # Draw # def draw(self): GLGeometricBase.draw(self) ColorMixin.draw(self) vb = context.application.vis_backend vb.draw_sphere(self.radius, self.quality) # # Revalidation # def revalidate_bounding_box(self): GLGeometricBase.revalidate_bounding_box(self) self.bounding_box.extend_with_corners(numpy.array([ [-self.radius, -self.radius, -self.radius], [ self.radius, self.radius, self.radius] ]))
class Bond(Vector): info = ModelObjectInfo("plugins/molecular/bond.svg") authors = [authors.toon_verstraelen] # # State # def initnonstate(self): Vector.initnonstate(self) self.handlers = {} # # Properties # def set_quality(self, quality, init=False): self.quality = quality if not init: self.invalidate_draw_list() def set_bond_type(self, bond_type, init=False): self.bond_type = bond_type if not init: self.invalidate_draw_list() properties = [ Property("quality", 15, lambda self: self.quality, set_quality), Property("bond_type", BOND_SINGLE, lambda self: self.bond_type, set_bond_type) ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo("Markup", (1, 3), fields.faulty.Int( label_text="Quality", attribute_name="quality", minimum=3, )), DialogFieldInfo("Molecular", (6, 1), fields.edit.ComboBox( choices=[ (BOND_SINGLE, "Single bond"), (BOND_DOUBLE, "Double bond"), (BOND_TRIPLE, "Triple bond"), (BOND_HYBRID, "Hybrid bond"), (BOND_HYDROGEN, "Hydrogen bond"), ], label_text="Bond type", attribute_name="bond_type", )), ]) # # References # def define_target(self, reference, new_target): Vector.define_target(self, reference, new_target) self.handlers[new_target] = [ new_target.connect("on_number_changed", self.atom_property_changed), new_target.connect("on_user_radius_changed", self.atom_property_changed), new_target.connect("on_user_color_changed", self.atom_property_changed), ] def undefine_target(self, reference, old_target): Vector.undefine_target(self, reference, old_target) for handler in self.handlers[old_target]: old_target.disconnect(handler) def check_target(self, reference, target): return isinstance(target, context.application.plugins.get_node("Atom")) def atom_property_changed(self, atom): self.invalidate_boundingbox_list() self.invalidate_draw_list() # # Draw # def draw(self): Vector.draw(self) if self.length <= 0: return half_length = 0.5 * (self.end_position - self.begin_position) if half_length <= 0: return half_radius = 0.5 * (self.begin_radius + self.end_radius) begin = self.children[0].target end = self.children[1].target vb = context.application.vis_backend vb.set_color(*begin.get_color()) vb.translate(0.0, 0.0, self.begin_position) vb.draw_cone(self.begin_radius, half_radius, half_length, self.quality) vb.translate(0.0, 0.0, half_length) vb.set_color(*end.get_color()) vb.draw_cone(half_radius, self.end_radius, half_length, self.quality) # # Revalidation # def revalidate_bounding_box(self): Vector.revalidate_bounding_box(self) if self.length > 0: temp = {True: self.begin_radius, False: self.end_radius}[self.begin_radius > self.end_radius] self.bounding_box.extend_with_point(numpy.array([-temp, -temp, self.begin_position])) self.bounding_box.extend_with_point(numpy.array([temp, temp, self.end_position])) def calc_vector_dimensions(self): Vector.calc_vector_dimensions(self) begin = self.children[0].target end = self.children[1].target if self.length <= 0.0: return c = (begin.get_radius() - end.get_radius()) / self.length if abs(c) > 1: self.begin_radius = 0 self.end_radius = 0 self.begin_position = 0 self.end_position = 0 else: scale = 0.4 s = numpy.sqrt(1 - c**2) self.begin_radius = scale * begin.get_radius() * s self.end_radius = scale * end.get_radius() * s self.begin_position = scale * c * begin.get_radius() self.end_position = self.length + scale * c * end.get_radius()
class Folder(ContainerBase): info = ModelObjectInfo("plugins/basic/folder.svg") authors = [authors.toon_verstraelen]
class Box(GLGeometricBase, ColorMixin): info = ModelObjectInfo("plugins/basic/box.svg") authors = [authors.toon_verstraelen] def initnonstate(self): GLGeometricBase.initnonstate(self, Complete) # # Properties # def set_size(self, size, init=False): self.size = size if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() properties = [ Property("size", numpy.array([1.0, 1.0, 1.0]), lambda self: self.size, set_size), ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo( "Geometry", (2, 6), fields.composed.ComposedArray( FieldClass=fields.faulty.Length, array_name="%s", suffices=["Width", "Height", "Depth"], label_text="Box size", attribute_name="size", )) ]) # # Draw # def draw(self): GLGeometricBase.draw(self) ColorMixin.draw(self) vb = context.application.vis_backend x, y, z = numpy.identity(3) sides = numpy.array([(x, y, z, z), (x, y, -z, -z), (y, z, x, x), (y, z, -x, -x), (z, x, y, y), (z, x, -y, -y)], float) sides[:, :3] *= 0.5 * self.size vb.draw_quads(*[(normal, [ a + b + c, a - b + c, -a - b + c, -a + b + c, ]) for a, b, c, normal in sides]) # # Revalidation # def revalidate_bounding_box(self): GLGeometricBase.revalidate_bounding_box(self) self.bounding_box.extend_with_corners( numpy.array([-0.5 * self.size, 0.5 * self.size]))
class Atom(GLGeometricBase, UserColorMixin): info = ModelObjectInfo("plugins/molecular/atom.svg") authors = [authors.toon_verstraelen] # # State # def initnonstate(self): GLGeometricBase.initnonstate(self, Translation) # # Properties # def set_user_radius(self, user_radius, init=False): self.user_radius = user_radius if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() def set_quality(self, quality, init=False): self.quality = quality if not init: self.invalidate_draw_list() def set_number(self, number, init=False): self.number = number atom_info = periodic[number] if atom_info.vdw_radius is not None: self.default_radius = atom_info.vdw_radius * 0.2 else: self.default_radius = 1.0 color = [atom_info.red, atom_info.green, atom_info.blue, 1.0] if None in color: self.default_color = numpy.array([0.7, 0.7, 0.7, 1.0], float) else: self.default_color = numpy.array(color, float) if not init: self.invalidate_draw_list() self.invalidate_boundingbox_list() properties = [ Property("user_radius", Undefined(0.5), lambda self: self.user_radius, set_user_radius, signal=True), Property("quality", 15, lambda self: self.quality, set_quality), Property("number", 6, lambda self: self.number, set_number, signal=True), ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo( "Geometry", (2, 9), fields.optional.CheckOptional( fields.faulty.Length( label_text="User defined radius", attribute_name="user_radius", low=0.0, low_inclusive=False, ))), DialogFieldInfo( "Markup", (1, 3), fields.faulty.Int( label_text="Quality", attribute_name="quality", minimum=3, )), DialogFieldInfo( "Molecular", (6, 0), fields.edit.Element( attribute_name="number", show_popup=False, )), ]) # # Draw # def get_radius(self): if isinstance(self.user_radius, Undefined): return self.default_radius else: return self.user_radius def draw(self): GLGeometricBase.draw(self) UserColorMixin.draw(self) vb = context.application.vis_backend vb.draw_sphere(self.get_radius(), self.quality) # # Revalidation # def revalidate_bounding_box(self): GLGeometricBase.revalidate_bounding_box(self) radius = self.get_radius() self.bounding_box.extend_with_corners( numpy.array([[-radius, -radius, -radius], [radius, radius, radius]])) # # Tools # def num_bonds(self): Bond = context.application.plugins.get_node("Bond") return sum( isinstance(reference.parent, Bond) for reference in self.references) def iter_bonds(self): Bond = context.application.plugins.get_node("Bond") for reference in self.references: referent = reference.parent if isinstance(referent, Bond): yield referent def iter_neighbors(self): for bond in self.iter_bonds(): first = bond.children[0].target if first == self: neighbor = bond.children[1].target else: neighbor = first if isinstance(neighbor, Atom): yield neighbor