def do(self): # A) collect all extra attributes of the selected nodes extra_attrs = {} for node in context.application.cache.nodes: for key, value in node.extra.iteritems(): other_value = extra_attrs.get(key) if other_value is None: extra_attrs[key] = value elif isinstance(other_value, Undefined): continue elif other_value != value: extra_attrs[key] = Undefined() for key, value in extra_attrs.items(): if isinstance(value, Undefined): continue for node in context.application.cache.nodes: other_value = node.extra.get(key) if other_value != value: extra_attrs[key] = Undefined() break # B) present the extra attributes in a popup window with editing features extra_dialog = ExtraDialog() modified_extra_attrs, remove_keys = extra_dialog.run(extra_attrs) if len(modified_extra_attrs) > 0 or len(remove_keys) > 0: # C) the modified extra attributes are applied to the select objects for node in context.application.cache.nodes: new_value = node.extra.copy() new_value.update(modified_extra_attrs) for remove_key in remove_keys: new_value.pop(remove_key, None) primitive.SetProperty(node, "extra", new_value)
def default_parameters(cls): result = Parameters() result.n = 5 result.m = 1 result.flat = False result.max_length = 50 * angstrom result.max_error = 0.01 * angstrom result.tube_length = Undefined(50 * angstrom) return result
def write(self): if self.get_active() and self.changed(): representation = self.read_from_widget() if self.get_sensitive(): self.save_history(representation) value = self.convert_to_value(representation) else: value = Undefined(self.convert_to_value(representation)) self.write_to_instance(value, self.instance)
def fn(): context.application.model.file_open("test/input/silica_layer.zml") parameters = Parameters() parameters.n = 10 parameters.m = 4 parameters.flat = False parameters.max_length = 300 * angstrom parameters.max_error = 0.01 * angstrom parameters.tube_length = Undefined(0.01 * angstrom) CreateTube = context.application.plugins.get_action("CreateTube") assert CreateTube.analyze_selection(parameters) CreateTube(parameters)
def ask_parameters(self): if len(context.application.cache.nodes) == 1: if not isinstance(self.parameters.connect_description2, Undefined): self.parameters.connect_description2 = Undefined( self.parameters.connect_description2) if not isinstance(self.parameters.repulse_description2, Undefined): self.parameters.repulse_description2 = Undefined( self.parameters.repulse_description2) else: if isinstance(self.parameters.connect_description2, Undefined): self.parameters.connect_description2 = self.parameters.connect_description2.value if isinstance(self.parameters.repulse_description2, Undefined): self.parameters.repulse_description2 = self.parameters.repulse_description2.value node1, node2 = context.application.cache.nodes relative_rotation = node2.get_frame_relative_to(node1.parent) if isinstance(self.parameters.rotation2, Undefined): self.parameters.rotation2 = Undefined(relative_rotation) else: self.parameters.rotation2 = relative_rotation if self.parameters_dialog.run(self.parameters) != gtk.RESPONSE_OK: self.parameters.clear() return
class UserColorMixin(gobject.GObject): __metaclass__ = NodeClass # # Properties # def set_user_color(self, user_color, init=False): self.user_color = user_color if not init: self.invalidate_draw_list() properties = [ Property("user_color", Undefined(numpy.array([0.7, 0.7, 0.7, 1.0])), lambda self: self.user_color, set_user_color, signal=True) ] # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo( "Markup", (1, 7), fields.optional.CheckOptional( fields.edit.Color( label_text="User defined color", attribute_name="user_color", ))), ]) # # Draw # def get_color(self): if isinstance(self.user_color, Undefined): return self.default_color else: return self.user_color def draw(self): context.application.vis_backend.set_color(*self.get_color())
def default_parameters(cls): rotation2 = Rotation.from_properties(0.0, [1, 0, 0], False) result = Parameters() result.connect_description1 = (Expression("True"), Expression("node.get_radius()")) result.repulse_description1 = (Expression("True"), Expression("node.get_radius()")) result.connect_description2 = (Expression("True"), Expression("node.get_radius()")) result.repulse_description2 = (Expression("True"), Expression("node.get_radius()")) result.action_radius = 7 * angstrom result.distance_tolerance = 0.1 * angstrom result.hit_tolerance = 0.1 * angstrom result.allow_inversions = True result.minimum_triangle_size = 0.1 * angstrom result.rotation_tolerance = 0.05 result.rotation2 = Undefined(rotation2) return result
def fn(): context.application.model.file_open("test/input/precursor.zml") context.application.main.select_nodes( context.application.model.universe.children) ScanForConnections = context.application.plugins.get_action( "ScanForConnections") parameters = ScanForConnections.default_parameters() parameters.connect_description1 = ( Expression( "isinstance(node, Atom) and node.number == 8 and node.num_bonds() == 1" ), Expression("node.get_radius()"), ) parameters.repulse_description1 = ( Expression( "isinstance(node, Atom) and (node.number == 8 or node.number == 14)" ), Expression("node.get_radius()*1.5"), ) parameters.action_radius = 4 * angstrom parameters.hit_tolerance = 0.1 * angstrom parameters.allow_inversions = True parameters.minimum_triangle_size = 0.1 * angstrom parameters.rotation2 = Undefined() assert ScanForConnections.analyze_selection(parameters) ScanForConnections(parameters) # Try to save the result to file an open it again. context.application.model.file_save("test/output/tmp.zml") FileNew = context.application.plugins.get_action("FileNew") FileNew() context.application.model.file_open("test/output/tmp.zml") # Do some consistency tests on the connection scanner results: scan_results = context.application.model.folder.children[0] for quality, transformation, pairs, inverse_pairs in scan_results.get_connections( ): assert len(pairs) >= 3 if len(inverse_pairs) > 0: assert len(pairs) == len(inverse_pairs) # Test for the first case that the indicated atom pairs are indeed # overlapping. context.application.main.select_nodes([scan_results]) ShowConscanResultsWindow = context.application.plugins.get_action( "ShowConscanResultsWindow") assert ShowConscanResultsWindow.analyze_selection() ShowConscanResultsWindow() csrw = ShowConscanResultsWindow.conscan_results_window csrw.tree_selection.select_path(0) action = CustomAction("Apply connection") csrw.apply_normal() action.finish() quality, transformation, pairs, inverse_pairs = scan_results.connections[ 0] for atom1, atom2 in pairs: f1 = atom1().get_absolute_frame() f2 = atom2().get_absolute_frame() d = numpy.linalg.norm(f1.t - f2.t) assert d < 1e-5 csrw.window.hide()
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