def set_transformation(self, transformation, init=False): if not transformation.__class__ == self.Transformation: # create an object of the proper type and take only the attributes # of interest. if isinstance(transformation, Translation): t = transformation.t else: t = None if isinstance(transformation, Rotation): r = transformation.r else: r = None if self.Transformation == Translation: if t is None: transformation = Translation.identity() else: transformation = Translation(t) elif self.Transformation == Rotation: if r is None: transformation = Rotation.identity() else: transformation = Rotation(r) else: # self.Transformation == Complete: if r is None: r = numpy.identity(3, float) if t is None: t = numpy.zeros(3, float) transformation = Complete(r, t) self.transformation = transformation if not init: self.invalidate_transformation_list()
def reset(self): config = context.application.configuration self.rotation_center = Translation.identity() self.rotation = Rotation.identity() self.eye = Translation([0, 0, config.viewer_distance]) self.opening_angle = config.opening_angle self.window_size = config.window_size self.window_depth = config.window_depth
def calc_vector_dimensions(self): relative_translation = self.shortest_vector_relative_to(self.parent) if relative_translation is None: self.length = 0 else: self.length = numpy.sqrt( numpy.dot(relative_translation, relative_translation)) if self.length > 0: t = self.children[0].translation_relative_to(self.parent) c = relative_translation[2] / self.length if c >= 1.0: self.orientation = Translation(t) elif c <= -1.0: alpha = numpy.pi axis = numpy.array([1.0, 0.0, 0.0]) self.orientation = Complete.from_properties( alpha, axis, False, t) else: x, y = relative_translation[0], relative_translation[1] if abs(x) < abs(y): signy = {True: 1, False: -1}[y >= 0] a = -signy b = signy * x / y else: signx = {True: 1, False: -1}[x >= 0] a = -signx * y / x b = signx alpha = numpy.arccos(c) axis = numpy.array([a, b, 0.0]) self.orientation = Complete.from_properties( alpha, axis, False, t)
def do(self): cache = context.application.cache graph = create_molecular_graph(cache.nodes) parent = cache.node Frame = context.application.plugins.get_node("Frame") for group in graph.independent_vertices: atoms = [graph.molecule.atoms[i] for i in group] new_positions = self.calc_new_positions(group, atoms, graph, parent) if new_positions is None: # this happens for groups of atoms that are inherently periodic. continue frame = Frame(name=chemical_formula(atoms)[1]) primitive.Add(frame, parent, index=0) for node, atom in zip(group, atoms): primitive.Move(atom, frame) new_position = new_positions[node] translation = Translation( atom.get_parentframe_up_to(parent).inv * new_position) primitive.SetProperty(atom, "transformation", translation) for atom in atoms: # take a copy of the references since they are going to be # refreshed (changed and reverted) during the loop. for reference in list(atom.references): referent = reference.parent if referent.parent != frame: has_to_move = True for child in referent.children: if child.target.parent != frame: has_to_move = False break if has_to_move: primitive.Move(referent, frame)
def fn(): context.application.model.file_open("test/input/core_objects.zml") context.application.main.toggle_selection(context.application.model.universe.children[3], on=True) parameters = Parameters() parameters.translation = Translation([2.0, 4.1, -1.0]) TranslateDialog = context.application.plugins.get_action("TranslateDialog") assert TranslateDialog.analyze_selection(parameters) TranslateDialog(parameters)
def fn(): FileNew = context.application.plugins.get_action("FileNew") FileNew() context.application.main.select_nodes([context.application.model.universe]) Frame = context.application.plugins.get_node("Frame") frame = Frame(transformation=Translation(numpy.random.uniform(-5, 5, 3))) context.application.model.universe.add(frame) frame.set_transformation(Rotation.random())
def reset(self): config = context.application.configuration self.rotation_center = Translation.identity() self.rotation = Rotation.identity() self.eye = Translation([0,0,config.viewer_distance]) self.opening_angle = config.opening_angle self.window_size = config.window_size self.window_depth = config.window_depth
def do_translation(self, vector, drawing_area): camera = context.application.camera tmp = vector.copy() tmp[2] = 0 transformed_vector = numpy.dot(self.eye_rotation, tmp) new_eye_t = camera.eye.t.copy() new_eye_t[:2] -= vector[:2] camera.rotation_center = Translation(camera.rotation_center.t + transformed_vector) if (camera.opening_angle > 0): new_eye_t[2] -= vector[2] else: window_size = camera.window_size * (1 + 0.01 * vector[-1]) if window_size < 0.001: window_size = 0.001 elif window_size > 1000: window_size = 1000 camera.window_size = window_size camera.eye = Translation(new_eye_t) drawing_area.queue_draw()
def fn(): context.application.model.file_open("test/input/core_objects.zml") context.application.main.toggle_selection(context.application.model.universe.children[3], on=True) parameters = Parameters() parameters.center = Translation([2.0, 4.1, -1.0]) parameters.rotation = Rotation.from_properties(1.0, numpy.array([0.1, 1.4, 0.3]), False) RotateAboutAxisDialog = context.application.plugins.get_action("RotateAboutAxisDialog") assert RotateAboutAxisDialog.analyze_selection(parameters) RotateAboutAxisDialog(parameters)
def compute_transformations(self): Scanner.compute_transformations(self) if self.allow_inversions: # derive the connections with inversion rotations, based on those # without inversion rotations new_connections = [] maximum = len(self.connections) for progress, connection in enumerate(self.connections): self.send(ProgressMessage("mirror", progress, maximum)) new = copy.deepcopy(connection) mirror = (Translation(connection.triangle1.center) * Rotation.from_properties( numpy.pi, connection.triangle1.normal, True) * Translation(-connection.triangle1.center)) new.set_transformation(mirror * new.transformation) new_connections.append(new) self.connections.extend(new_connections) self.send(ProgressMessage("mirror", maximum, maximum))
def do(self): cache = context.application.cache parent = cache.node unit_cell = None if isinstance(parent, UnitCell): unit_cell = parent Atom = context.application.plugins.get_node("Atom") atoms = [] coordinates = [] for child in parent.children: if isinstance(child, Atom): atoms.append(child) coordinates.append(child.transformation.t) coordinates = numpy.array(coordinates) cf = ClusterFactory() for i0, i1, delta, distance in PairSearchIntra( coordinates, periodic.max_radius * 0.4, unit_cell): atom0 = atoms[i0] atom1 = atoms[i1] if atom0.number == atom1.number: if distance < periodic[atom0.number].vdw_radius * 0.4: cf.add_related(atom0, atom1) clusters = cf.get_clusters() del cf # define the new singles singles = [] for cluster in clusters: number = iter(cluster.items).next().number single = Atom(name="Single " + periodic[number].symbol) single.set_number(number) singles.append((single, list(cluster.items))) # calculate their positions for single, overlappers in singles: # in the following algorithm, we suppose that the cluster of # atoms is small compared to the parent's periodic sizes # (if the parent is a periodic system) first_pos = overlappers[0].transformation.t delta_to_mean = numpy.zeros(3, float) for atom in overlappers[1:]: delta_to_mean += parent.shortest_vector(atom.transformation.t - first_pos) delta_to_mean /= float(len(overlappers)) single.set_transformation(Translation(first_pos + delta_to_mean)) # modify the model for single, overlappers in singles: lowest_index = min([atom.get_index() for atom in overlappers]) primitive.Add(single, parent, index=lowest_index) for atom in overlappers: while len(atom.references) > 0: primitive.SetTarget(atom.references[0], single) primitive.Delete(atom)
def add_hydrogens(atom): existing_bonds = list(atom.iter_bonds()) bond_length = bonds.get_length(atom.number, 1, BOND_SINGLE) num_hydrogens = self.parameters.num_hydrogens if len(existing_bonds) == 0: t = atom.transformation.t + numpy.array([0, bond_length, 0]) H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) existing_bonds.append(bond) num_hydrogens -= 1 main_direction = numpy.zeros(3, float) for bond in existing_bonds: shortest_vector = bond.shortest_vector_relative_to(atom.parent) if bond.children[1].target == atom: shortest_vector *= -1 main_direction += shortest_vector main_direction /= numpy.linalg.norm(main_direction) normal = random_orthonormal(main_direction) rotation = Rotation.from_properties( 2 * numpy.pi / float(num_hydrogens), main_direction, False) h_pos = bond_length * ( main_direction * numpy.cos(self.parameters.valence_angle) + normal * numpy.sin(self.parameters.valence_angle)) for i in range(num_hydrogens): t = atom.transformation.t + h_pos H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) h_pos = rotation * h_pos
def ask_parameters(self): cache = context.application.cache nodes = cache.nodes last = cache.last next_to_last = cache.next_to_last if isinstance(last, Vector): if (len(nodes) >= 2) and isinstance(next_to_last, Vector): parent = nodes[-2].parent b1 = last.children[0].translation_relative_to(parent) e1 = last.children[1].translation_relative_to(parent) b2 = next_to_last.children[0].translation_relative_to(parent) e2 = next_to_last.children[1].translation_relative_to(parent) if (b1 is not None) and (e1 is not None) and ( b2 is not None) and (e2 is not None): angle = compute_angle(e1 - b1, e2 - b2) axis = numpy.cross(e1 - b1, e2 - b2) self.parameters.center = Translation(0.5 * (b1 + b2)) self.parameters.rotation = Rotation.from_properties( angle, axis, False) else: parent = next_to_last.parent b = last.children[0].translation_relative_to(parent) e = last.children[1].translation_relative_to(parent) if (b is not None) and (e is not None): self.parameters.center = Translation(b) self.parameters.rotation = Rotation.from_properties( numpy.pi * 0.25, e - b, False) elif isinstance(last, GLTransformationMixin) and isinstance( last.transformation, Translation): parent = last.parent self.parameters.center = Translation( last.get_frame_relative_to(parent).t) self.parameters.rotation = Rotation.identity() else: self.parameters.center = Translation( calculate_center(cache.translations)) if self.parameters_dialog.run(self.parameters) != gtk.RESPONSE_OK: self.parameters.clear()
def ask_parameters(self): cache = context.application.cache last = cache.last parent = cache.parent_of_translated_nodes if isinstance(last, Vector): b = last.children[0].translation_relative_to(parent) e = last.children[1].translation_relative_to(parent) if (b is not None) and (e is not None): self.parameters.translation = Translation(e - b) else: self.parameters = self.last_parameters() if self.parameters_dialog.run(self.parameters) != gtk.RESPONSE_OK: self.parameters.clear()
def fn(): FileNew = context.application.plugins.get_action("FileNew") FileNew() for index in xrange(4): context.application.main.select_nodes([context.application.model.universe]) Point = context.application.plugins.get_node("Point") point = Point(transformation=Translation(numpy.random.uniform(-5, 5, 3))) context.application.model.universe.add(point) context.application.main.select_nodes(context.application.model.universe.children) AddTetraeder = context.application.plugins.get_action("AddTetraeder") assert AddTetraeder.analyze_selection() AddTetraeder()
def __call__(self, f): Universe = context.application.plugins.get_node("Universe") universe = Universe() Folder = context.application.plugins.get_node("Folder") folder = Folder() Atom = context.application.plugins.get_node("Atom") counter = 1 atom_index = 0 for line in f: #if len(line) != 81: # raise FilterError("Each line in a PDB file must count 80 characters, error at line %i, len=%i" % (counter, len(line)-1)) if line.startswith("ATOM"): extra = {"index": atom_index} atom_info = periodic[line[76:78].strip()] try: t = numpy.array([ float(line[30:38].strip()), float(line[38:46].strip()), float(line[46:54].strip()) ]) * angstrom except ValueError: raise FilterError( "Error while reading PDB file: could not read coordinates at line %i." % counter) atom = Atom(name=line[12:16].strip(), number=atom_info.number, transformation=Translation(t), extra=extra) universe.add(atom) atom_index += 1 elif line.startswith("CRYST1"): space_group = line[55:66].strip().upper() if space_group != "P 1": raise FilterError( "Error while reading PDB file: only unit cells with space group P 1 are supported." ) a = float(line[6:15].strip()) * angstrom b = float(line[15:24].strip()) * angstrom c = float(line[24:33].strip()) * angstrom alpha = float(line[33:40].strip()) * numpy.pi / 180 beta = float(line[40:47].strip()) * numpy.pi / 180 gamma = float(line[47:54].strip()) * numpy.pi / 180 universe.set_cell( UnitCell.from_parameters3([a, b, c], [alpha, beta, gamma])) counter += 1 return [universe, folder]
def fn(): FileNew = context.application.plugins.get_action("FileNew") FileNew() import zeobuilder.actions.primitive from molmod import Translation for index in xrange(3): context.application.main.select_nodes([context.application.model.universe]) Point = context.application.plugins.get_node("Point") point = Point(transformation=Translation(numpy.random.uniform(-1, 1, 3))) context.application.model.universe.add(point) context.application.main.select_nodes(context.application.model.universe.children) AddPlane = context.application.plugins.get_action("AddPlane") assert AddPlane.analyze_selection() AddPlane()
def do(self): cache = context.application.cache for node in cache.nodes: child_translations = [] translated_children = [] for child in node.children: if isinstance(child, GLTransformationMixin) and isinstance( child.transformation, Translation): if child.get_fixed(): translated_children = [] break translated_children.append(child) child_translations.append(child.transformation) if len(translated_children) > 0: translation = Translation(calculate_center(child_translations)) CenterAlignBase.do(self, node, translated_children, translation)
def fn(): FileNew = context.application.plugins.get_action("FileNew") FileNew() Atom = context.application.plugins.get_node("Atom") Frame = context.application.plugins.get_node("Frame") frame = Frame() context.application.model.universe.add(frame) atom1 = Atom() atom2 = Atom(transformation=Translation([1.1, 0.1, 0.03])) frame.add(atom1) frame.add(atom2) CenterOfMassAndPrincipalAxes = context.application.plugins.get_action( "CenterOfMassAndPrincipalAxes") context.application.main.select_nodes( [context.application.model.universe.children[0]]) assert CenterOfMassAndPrincipalAxes.analyze_selection() CenterOfMassAndPrincipalAxes()
def do(self): cache = context.application.cache parent = cache.common_parent while not parent.check_add(Point): parent = parent.parent vector_sum = numpy.zeros(3, float) num_vectors = 0 for node in cache.nodes: if isinstance(node, GLTransformationMixin) and \ isinstance(node.transformation, Translation): vector_sum += node.get_frame_relative_to(parent).t num_vectors += 1 point = Point(name="Average", transformation=Translation(vector_sum / num_vectors)) primitive.Add(point, parent)
def do(self): cache = context.application.cache for node in cache.nodes: translated_children = [] for child in node.children: if isinstance(child, GLTransformationMixin) and isinstance( child.transformation, Translation): if child.get_fixed(): translated_children = [] break translated_children.append(child) if len(translated_children) == 0: continue mass, com = compute_center_of_mass(iter_particles(node)) if mass == 0.0: continue CenterAlignBase.do(self, node, translated_children, Translation(com))
def __call__(self, f): try: xyz_reader = XYZReader(f) molecule = xyz_reader.get_first_molecule() except IOError: raise FilterError( "Could not read the first frame from the XYZ file. Incorrect file format." ) Universe = context.application.plugins.get_node("Universe") universe = Universe() Folder = context.application.plugins.get_node("Folder") folder = Folder() title = molecule.title.strip() if len(title) > 0: universe.name = title Atom = context.application.plugins.get_node("Atom") Point = context.application.plugins.get_node("Point") for index, number, symbol, coordinate in zip(xrange(molecule.size), molecule.numbers, xyz_reader.symbols, molecule.coordinates): extra = {"index": index} transl = Translation(coordinate) if number == 0: atom = Point(name=symbol, extra=extra, transformation=transl) else: atom = Atom(name=symbol, number=number, extra=extra, transformation=transl) universe.add(atom) geometries = [] for title, coordinates in xyz_reader: geometries.append(coordinates) return [universe, folder]
def load_molecule(self, parent, molecule): parent.extra.update(self.load_extra(molecule.extra)) Atom = context.application.plugins.get_node("Atom") for counter, number, coordinate in zip(xrange(molecule.size), molecule.numbers, molecule.coordinates): extra = self.load_extra(molecule.atoms_extra.get(counter, {})) extra["index"] = counter atom_record = periodic[number] atom = Atom( name=atom_record.symbol, number=number, extra=extra, transformation=Translation(coordinate) ) parent.add(atom) counter += 1 if molecule.graph is not None: Bond = context.application.plugins.get_node("Bond") for counter, edge in enumerate(molecule.graph.edges): extra = self.load_extra(molecule.bonds_extra.get(edge, {})) name = "Bond %i" % counter i, j = edge bond = Bond(name=name, targets=[parent.children[i],parent.children[j]], extra=extra) parent.add(bond)
def do(self): Atom = context.application.plugins.get_node("Atom") cache = context.application.cache for spring in list(cache.nodes): atom1, atom2 = spring.get_targets() if isinstance(atom1, Atom) and isinstance(atom2, Atom): t = 0.5 * (atom1.get_frame_relative_to(spring.parent).t + atom2.get_frame_relative_to(spring.parent).t) replacement = Atom(name="Merge of %s and %s" % (atom1.name, atom2.name), number=max([atom1.number, atom2.number]), transformation=Translation(t)) primitive.Add(replacement, spring.parent, spring.get_index()) atoms = set([atom1, atom2]) for atom in atoms: while len(atom.references) > 0: primitive.SetTarget(atom.references[0], replacement) primitive.Delete(spring) for atom in atoms: primitive.Delete(atom)
def interactive_init(self): InteractiveWithMemory.interactive_init(self) cache = context.application.cache if len(cache.nodes) == 1: self.victim = cache.node helper = None else: self.victim = cache.next_to_last helper = cache.last self.rotation_axis = None self.changed = False rotation_center_object = None if helper is not None: # take the information out of the helper nodes if isinstance(helper, Vector): b = helper.children[0].translation_relative_to( self.victim.parent) e = helper.children[1].translation_relative_to( self.victim.parent) if not ((b is None) or (e is None)): rotation_center_object = helper.children[0].target self.rotation_axis = e - b norm = numpy.dot(self.rotation_axis, self.rotation_axis) if norm > 0.0: self.rotation_axis /= norm else: self.rotation_axis = None else: rotation_center_object = helper else: rotation_center_object = self.victim self.rotation_center = Translation( rotation_center_object.get_frame_relative_to(self.victim.parent).t) drawing_area = context.application.main.drawing_area camera = context.application.camera self.screen_rotation_center = drawing_area.camera_to_screen( camera.object_to_camera(rotation_center_object)) self.eye_rotation = camera.object_eye_rotation(self.victim) self.old_transformation = self.victim.transformation
def get_new(self, position): if self.current_object == "Fragment": filename = context.get_share_filename('fragments/%s.cml' % self.current_fragment) molecule = load_cml(filename)[0] Frame = context.application.plugins.get_node("Frame") new = Frame(name=self.current_fragment) load_filter = context.application.plugins.get_load_filter('cml') load_filter.load_molecule(new, molecule) else: NewClass = context.application.plugins.get_node( self.current_object) new = NewClass() if self.current_object == "Atom": new.set_number(self.atom_number) new.set_name(periodic[self.atom_number].symbol) translation = Translation(position) primitive.Transform(new, translation) return new
def coords_to_zeobuilder(org_coords, opt_coords, atoms, parent, graph=None): if graph == None: groups = [numpy.arange(len(atoms))] else: # if the molecular graph has disconnected islands, then each independent # part is treated seperately in the loop below groups = graph.independent_vertices for group in groups: group_org = org_coords[group] group_opt = opt_coords[group] # Transform the guessed geometry as to overlap with the original geometry transf = superpose(group_org, group_opt) group_opt = transf * group_opt # Put coordinates of guessed geometry back into Zeobuilder model for i, atomindex in enumerate(group): atom = atoms[atomindex] # Make sure atoms in subframes are treated properly transf = atom.parent.get_frame_relative_to(parent) org_pos = atom.transformation.t opt_pos = transf.inv * group_opt[i] primitive.Transform(atom, Translation(opt_pos - org_pos))
def do(self): cache = context.application.cache # Translate where possible, if necessary translated_nodes = cache.translated_nodes if len(translated_nodes) > 0: if isinstance(cache.last, GLTransformationMixin) and \ isinstance(cache.last.transformation, Translation): absolute_inversion_center = cache.last.get_absolute_frame().t else: absolute_inversion_center = numpy.zeros(3, float) victims_by_parent = list_by_parent(cache.transformed_nodes) for parent, victims in victims_by_parent.iteritems(): local_inversion_center = parent.get_absolute_frame( ).inv * absolute_inversion_center for victim in victims: translation = Translation( 2 * (local_inversion_center - victim.transformation.t)) primitive.Transform(victim, translation) # Apply an inversion rotation where possible inversion = Rotation(-numpy.identity(3, float)) for victim in cache.rotated_nodes: primitive.Transform(victim, inversion, after=False)
def get_model_center(self): universe = context.application.model.universe if universe is None: return Translation.identity() else: return universe.model_center
def initnonstate(self): GLPeriodicContainer.initnonstate(self) self.model_center = Translation.identity()
def add_hydrogens(atom): existing_bonds = list(atom.iter_bonds()) num_bonds = len(existing_bonds) bond_length = bonds.get_length(atom.number, 1, BOND_SINGLE) if num_bonds == 0: t = atom.transformation.t + numpy.array([0, bond_length, 0]) H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) existing_bonds.append(bond) num_bonds = 1 used_valence = 0 oposite_direction = numpy.zeros(3, float) for bond in existing_bonds: shortest_vector = bond.shortest_vector_relative_to(atom.parent) if bond.children[1].target == atom: shortest_vector *= -1 oposite_direction -= shortest_vector if bond.bond_type == BOND_SINGLE: used_valence += 1 elif bond.bond_type == BOND_DOUBLE: used_valence += 2 elif bond.bond_type == BOND_TRIPLE: used_valence += 3 oposite_direction /= numpy.linalg.norm(oposite_direction) num_hydrogens = valence_el( atom.number) - 2 * lone_pairs(atom.number) - used_valence if num_hydrogens <= 0: return hybride_count = num_hydrogens + lone_pairs( atom.number) + num_bonds - (used_valence - num_bonds) num_sites = num_hydrogens + lone_pairs(atom.number) rotation = Rotation.from_properties( 2 * numpy.pi / float(num_sites), oposite_direction, False) opening_key = (hybride_count, num_sites) opening_angle = self.opening_angles.get(opening_key) if opening_angle is None: return if num_bonds == 1: first_bond = existing_bonds[0] other_atom = first_bond.children[0].target if other_atom == atom: other_atom = first_bond.children[1].target other_bonds = [ bond for bond in other_atom.iter_bonds() if bond != first_bond ] if len(other_bonds) > 0: normal = other_bonds[0].shortest_vector_relative_to( atom.parent) normal -= numpy.dot(normal, oposite_direction) * oposite_direction normal /= numpy.linalg.norm(normal) if other_bonds[0].children[0].target == other_atom: normal *= -1 else: normal = random_orthonormal(oposite_direction) elif num_bonds == 2: normal = numpy.cross( oposite_direction, existing_bonds[0].shortest_vector_relative_to(atom.parent)) normal /= numpy.linalg.norm(normal) elif num_bonds == 3: normal = random_orthonormal(oposite_direction) else: return h_pos = bond_length * (oposite_direction * numpy.cos(opening_angle) + normal * numpy.sin(opening_angle)) for i in range(num_hydrogens): t = atom.transformation.t + h_pos H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) h_pos = rotation * h_pos
def replace(self, gl_object): if not gl_object.get_fixed(): new = self.get_new(gl_object.transformation.t) # select a target object, i.e. the one the will be connected with # the bonds/vectors/... of the replaced object if (self.current_object == "Fragment"): # fragments are inserted as frames # take atom with index 1 as target target_object = new.children[1] else: target_object = new # check if all connections to the replaced object are applicable # to the new object. if not, then do not perform the replacement # and return early. for reference in gl_object.references[::-1]: if not reference.check_target(target_object): return # add the new object parent = gl_object.parent primitive.Add(new, parent) if (self.current_object == "Fragment"): # Fix the rotation and translation of the molecular fragment. # Rotation Bond = context.application.plugins.get_node("Bond") if len(gl_object.references) == 1 and isinstance( gl_object.references[0].parent, Bond): bond1 = gl_object.references[0].parent direction1 = bond1.shortest_vector_relative_to(parent) if bond1.children[0].target != gl_object: direction1 *= -1 bond2 = new.children[0].references[0].parent direction2 = bond2.shortest_vector_relative_to(parent) if bond2.children[0].target != target_object: direction2 *= -1 axis = numpy.cross(direction2, direction1) if numpy.linalg.norm(axis) < 1e-8: axis = random_orthonormal(direction1) angle = compute_angle(direction1, direction2) rotation = Rotation.from_properties(angle, axis, False) primitive.Transform(new, rotation) else: bond1 = None # Tranlsation pos_old = new.children[1].get_frame_relative_to(parent).t pos_new = gl_object.transformation.t translation = Translation(pos_new - pos_old) primitive.Transform(new, translation) if bond1 != None: # bond length old_length = numpy.linalg.norm(direction1) new_length = bonds.get_length( new.children[1].number, bond1.get_neighbor(gl_object).number) translation = Translation(-direction1 / old_length * (new_length - old_length)) primitive.Transform(new, translation) # let the references to the replaced object point to the new object for reference in gl_object.references[::-1]: try: primitive.SetTarget(reference, target_object) except primitive.PrimitiveError: primitive.Delete(reference.parent) # delete the replaced object primitive.Delete(gl_object) if (self.current_object == "Fragment"): # Delete the first atom in the fragment primitive.Delete(new.children[0]) # Unframe the fragment UnframeAbsolute = context.application.plugins.get_action( "UnframeAbsolute") UnframeAbsolute([new])
def default_parameters(cls): result = Parameters() result.center = Translation.identity() result.rotation = Rotation.identity() return result
def compute_transformation(self, connection): #print connection.pairs triangle1 = connection.triangle1 triangle2 = connection.triangle2 triangles = [triangle1, triangle2] #print "BEFORE TRANSFORMING\n" #for triangle in triangles: # #print "-------" # for coordinate in triangle.coordinates: # #print coordinate #print "---------" # *** t1: translation of triangle in geometry2 to origin t1 = Translation(-triangle2.center) #print triangle2.center triangle2.apply_to_coordinates(t1) # also move triangle1 to the origin t_tmp = Translation(-triangle1.center) # was t0 triangle1.apply_to_coordinates(t_tmp) #print "AFTER CENTERING (T1 and T0)" #for triangle in triangles: # #print "-------" # for coordinate in triangle.coordinates: # #print coordinate # *** r2: make the two triangles coplanar #print "NORMALS" #print triangle1.normal #print triangle2.normal rotation_axis = numpy.cross(triangle2.normal, triangle1.normal) if numpy.dot(rotation_axis, rotation_axis) < 1e-8: rotation_axis = random_orthonormal(triangle2.normal) rotation_angle = angle(triangle2.normal, triangle1.normal) #print "R2 %s, %s" % (rotation_angle/numpy.pi*180, rotation_axis) r2 = Rotation.from_properties(rotation_angle, rotation_axis, False) triangle2.apply_to_coordinates(r2) #print "AFTER R2" #for triangle in triangles: # #print "-------" # for coordinate in triangle.coordinates: # #print coordinate # bring both triangles in the x-y plane, by a rotation around an axis # orthogonal to the Z-axis. rotation_axis = numpy.array( [triangle1.normal[1], -triangle1.normal[0], 0.0], float) if numpy.dot(rotation_axis, rotation_axis) < 1e-8: rotation_axis = numpy.array([1.0, 0.0, 0.0], float) cos_angle = triangle1.normal[2] if cos_angle >= 1.0: rotation_angle = 0 elif cos_angle <= -1.0: rotation_angle = numpy.pi else: rotation_angle = numpy.arccos(cos_angle) #print "RT %s, %s" % (rotation_angle/numpy.pi*180, rotation_axis) r_flat = Rotation.from_properties(rotation_angle, rotation_axis, False) triangle1.apply_to_coordinates(r_flat) triangle2.apply_to_coordinates(r_flat) #print "AFTER RT" #for triangle in triangles: # #print "-------" # for coordinate in triangle.coordinates: # #print coordinate # *** r3: second rotation that makes both triangle coinced H = lambda a, b, c, d: a * c + b * d + (a + b) * (c + d) c = (H(triangle1.coordinates[0][0], triangle1.coordinates[1][0], triangle2.coordinates[0][0], triangle2.coordinates[1][0]) + H(triangle1.coordinates[0][1], triangle1.coordinates[1][1], triangle2.coordinates[0][1], triangle2.coordinates[1][1])) s = (H(triangle1.coordinates[0][1], triangle1.coordinates[1][1], triangle2.coordinates[0][0], triangle2.coordinates[1][0]) - H(triangle1.coordinates[0][0], triangle1.coordinates[1][0], triangle2.coordinates[0][1], triangle2.coordinates[1][1])) #if c > s: c, s = -c, -s #print "cos=%f sin=%f" % (c, s) rotation_angle = numpy.arctan2(s, c) #print "R3 %s, %s" % (rotation_angle/numpy.pi*180, triangle1.normal) r3 = Rotation.from_properties(rotation_angle, triangle1.normal, False) r_tmp = Rotation.from_properties(rotation_angle, numpy.array([0, 0, 1], float), False) triangle2.apply_to_coordinates(r_tmp) #print "AFTER R3" #for triangle in triangles: # #print "-------" # for coordinate in triangle.coordinates: # #print coordinate # t4: translate the triangle to the definitive coordinate t4 = Translation(triangle1.center) #print "AFTER T4" #for triangle in triangles: # #print "-------" # for coordinate in triangle.coordinates: # #print coordinate return t4 * r3 * r2 * t1
def default_parameters(cls): result = Parameters() result.translation = Translation.identity() return result