Exemple #1
0
 def on_bu_set_atom_clicked(self, button):
     self.edit_atom_number = FieldsDialogSimple(
         "Select atom number",
         fields.edit.Element(attribute_name="atom_number"),
         ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
          (gtk.STOCK_OK, gtk.RESPONSE_OK)))
     self.edit_atom_number.run(self)
     atom_symbol = periodic[self.atom_number].symbol
     self.la_current.set_label("Current: %s " % str(atom_symbol))
Exemple #2
0
 def __init__(self):
     self.atom_expression = Expression()
     FieldsDialogSimple.__init__(
         self, "Neighbor shells",
         fields.faulty.Expression(
             label_text="Atom expression (atom, graph)",
             attribute_name="atom_expression",
             history_name="atom_expression",
             width=250,
             height=150,
         ), (("Evaluate", RESPONSE_EVALUATE), ("Select", RESPONSE_SELECT),
             (gtk.STOCK_SAVE, RESPONSE_SAVE),
             (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)))
Exemple #3
0
    def do(self):
        edit_config = FieldsDialogSimple(
            "Zeobuilder configuration",
            context.application.configuration.create_main_field(),
            ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK))
        )

        class Settings(object):
            pass
        settings = Settings()
        settings.__dict__ = context.application.configuration.settings
        edit_config.run(settings)
        context.application.configuration.settings = settings.__dict__
Exemple #4
0
    def do(self):
        edit_config = FieldsDialogSimple(
            "Zeobuilder configuration",
            context.application.configuration.create_main_field(),
            ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
             (gtk.STOCK_OK, gtk.RESPONSE_OK)))

        class Settings(object):
            pass

        settings = Settings()
        settings.__dict__ = context.application.configuration.settings
        edit_config.run(settings)
        context.application.configuration.settings = settings.__dict__
Exemple #5
0
 def on_dialog_response(self, dialog, response_id):
     FieldsDialogSimple.on_dialog_response(self, dialog, response_id)
     if self.valid:
         self.atom_expression.variables = ("atom", "graph")
         self.atom_expression.compile_as("<atom_expression>")
         if response_id == RESPONSE_EVALUATE:
             self.evaluate()
             self.hide = False
         if response_id == RESPONSE_SELECT:
             self.select()
             self.hide = True
         elif response_id == RESPONSE_SAVE:
             self.save()
             self.hide = False
Exemple #6
0
 def on_dialog_response(self, dialog, response_id):
     FieldsDialogSimple.on_dialog_response(self, dialog, response_id)
     if self.valid:
         self.atom_expression.variables = ("atom", "graph")
         self.atom_expression.compile_as("<atom_expression>")
         if response_id == RESPONSE_EVALUATE:
             self.evaluate()
             self.hide = False
         if response_id == RESPONSE_SELECT:
             self.select()
             self.hide = True
         elif response_id == RESPONSE_SAVE:
             self.save()
             self.hide = False
Exemple #7
0
class EditSelectionFilter(Immediate):
    description = "Edit selection filter"
    menu_info = MenuInfo("default/_Select:preferences", "_Selection filter", order=(0, 3, 2, 0))
    authors = [authors.toon_verstraelen]

    selection_filter = FieldsDialogSimple(
        "Selection filter",
        fields.group.Table(fields=[
            fields.edit.CheckButton(
                label_text="Filter active",
                attribute_name="filter_active",
                show_popup=False,
            ),
            fields.faulty.Expression(
                label_text="Filter expression",
                attribute_name="filter_expression",
                show_popup=True,
                history_name="filter",
            )
        ]),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK))
    )

    @staticmethod
    def analyze_selection():
        # A) calling ancestor
        if not Immediate.analyze_selection(): return False
        # C) passed all tests:
        return True

    def do(self):
        self.selection_filter.run(context.application.main)
Exemple #8
0
    def on_set_parameters(self, menu, cell):
        from zeobuilder.gui.fields_dialogs import FieldsDialogSimple

        dialog = FieldsDialogSimple(
            "Set the cell parameters",
            CellParameters(
                attribute_name="cell",
                show_popup=False,
            ),
            ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK)),
        )

        parameters = Parameters()
        parameters.cell = cell
        if dialog.run(parameters) == gtk.RESPONSE_OK:
            self.field.write_to_widget(self.field.convert_to_representation(parameters.cell))
Exemple #9
0
    def on_set_parameters(self, menu, cell):
        from zeobuilder.gui.fields_dialogs import FieldsDialogSimple

        dialog = FieldsDialogSimple(
            "Set the cell parameters",
            CellParameters(
                attribute_name="cell",
                show_popup=False,
            ),
            ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
             (gtk.STOCK_OK, gtk.RESPONSE_OK)),
        )

        parameters = Parameters()
        parameters.cell = cell
        if dialog.run(parameters) == gtk.RESPONSE_OK:
            self.field.write_to_widget(
                self.field.convert_to_representation(parameters.cell))
Exemple #10
0
 def on_bu_set_atom_clicked(self, button):
     self.edit_atom_number = FieldsDialogSimple(
         "Select atom number",
         fields.edit.Element(attribute_name="atom_number"),
         ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK))
     )
     self.edit_atom_number.run(self)
     atom_symbol = periodic[self.atom_number].symbol
     self.la_current.set_label("Current: %s " % str(atom_symbol))
Exemple #11
0
 def __init__(self):
     self.atom_expression = Expression()
     FieldsDialogSimple.__init__(
         self,
         "Neighbor shells",
         fields.faulty.Expression(
             label_text="Atom expression (atom, graph)",
             attribute_name="atom_expression",
             history_name="atom_expression",
             width=250,
             height=150,
         ), (
             ("Evaluate", RESPONSE_EVALUATE),
             ("Select", RESPONSE_SELECT),
             (gtk.STOCK_SAVE, RESPONSE_SAVE),
             (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
         )
     )
Exemple #12
0
    def create_dialog(self):
        FieldsDialogSimple.create_dialog(self)

        self.list_view = gtk.TreeView(self.list_store)

        column = gtk.TreeViewColumn("Index", gtk.CellRendererText(), text=0)
        column.set_sort_column_id(0)
        self.list_view.append_column(column)

        column = gtk.TreeViewColumn("Number", gtk.CellRendererText(), text=1)
        column.set_sort_column_id(1)
        self.list_view.append_column(column)

        column = gtk.TreeViewColumn("Atom", gtk.CellRendererText(), text=2)
        column.set_sort_column_id(2)
        self.list_view.append_column(column)

        column = gtk.TreeViewColumn("Value", gtk.CellRendererText(), markup=3)
        column.set_sort_column_id(3)
        self.list_view.append_column(column)

        for index in xrange(1, self.max_shell_size + 1):
            column = gtk.TreeViewColumn("Shell %i" % index,
                                        gtk.CellRendererText(),
                                        markup=index + 3)
            column.set_sort_column_id(index + 3)
            self.list_view.append_column(column)

        selection = self.list_view.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)
        selection.connect("changed", self.on_selection_changed)

        self.scrolled_window = gtk.ScrolledWindow()
        self.scrolled_window.set_shadow_type(gtk.SHADOW_IN)
        self.scrolled_window.set_shadow_type(gtk.SHADOW_IN)
        self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
                                        gtk.POLICY_AUTOMATIC)
        self.scrolled_window.set_border_width(6)
        self.scrolled_window.add(self.list_view)
        self.scrolled_window.set_size_request(400, 300)
        self.scrolled_window.show_all()

        self.dialog.vbox.pack_start(self.scrolled_window)
Exemple #13
0
    def create_dialog(self):
        FieldsDialogSimple.create_dialog(self)

        self.list_view = gtk.TreeView(self.list_store)

        column = gtk.TreeViewColumn("Index", gtk.CellRendererText(), text=0)
        column.set_sort_column_id(0)
        self.list_view.append_column(column)

        column = gtk.TreeViewColumn("Number", gtk.CellRendererText(), text=1)
        column.set_sort_column_id(1)
        self.list_view.append_column(column)

        column = gtk.TreeViewColumn("Atom", gtk.CellRendererText(), text=2)
        column.set_sort_column_id(2)
        self.list_view.append_column(column)

        column = gtk.TreeViewColumn("Value", gtk.CellRendererText(), markup=3)
        column.set_sort_column_id(3)
        self.list_view.append_column(column)

        for index in xrange(1, self.max_shell_size+1):
            column = gtk.TreeViewColumn("Shell %i" % index, gtk.CellRendererText(), markup=index+3)
            column.set_sort_column_id(index+3)
            self.list_view.append_column(column)

        selection = self.list_view.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)
        selection.connect("changed", self.on_selection_changed)

        self.scrolled_window = gtk.ScrolledWindow()
        self.scrolled_window.set_shadow_type(gtk.SHADOW_IN)
        self.scrolled_window.set_shadow_type(gtk.SHADOW_IN)
        self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.scrolled_window.set_border_width(6)
        self.scrolled_window.add(self.list_view)
        self.scrolled_window.set_size_request(400, 300)
        self.scrolled_window.show_all()

        self.dialog.vbox.pack_start(self.scrolled_window)
Exemple #14
0
class TranslateDialog(ImmediateWithMemory):
    description = "Apply translation"
    menu_info = MenuInfo("default/_Object:tools/_Transform:dialogs",
                         "_Translate",
                         order=(0, 4, 1, 2, 1, 2))
    authors = [authors.toon_verstraelen]

    parameters_dialog = FieldsDialogSimple(
        "Translation",
        fields.composed.Translation(
            label_text="Translate with vector t",
            attribute_name="translation",
        ), ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
            (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        cache = context.application.cache
        if len(cache.translated_nodes) == 0: return False
        if cache.parent_of_translated_nodes is None: return False
        if cache.some_nodes_fixed: return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.translation = Translation.identity()
        return result

    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 do(self):
        for victim in context.application.cache.translated_nodes:
            primitive.Transform(victim, self.parameters.translation)
Exemple #15
0
class ScaleUnitCell(ImmediateWithMemory):
    description = "Scale the unit cell and its contents"
    menu_info = MenuInfo("default/_Object:tools/_Unit Cell:default",
                         "_Scale unit cell",
                         order=(0, 4, 1, 4, 0, 4))
    repeatable = False
    authors = [authors.toon_verstraelen]
    store_last_parameters = False

    parameters_dialog = FieldsDialogSimple(
        "Scale unit cell",
        fields.composed.CellMatrix(
            label_text="Cell dimensions",
            attribute_name="matrix",
        ), ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
            (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not Immediate.analyze_selection(): return False
        # B) validating
        universe = context.application.model.universe
        if sum(universe.cell.active) == 0: return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.matrix = context.application.model.universe.cell.matrix.copy()
        return result

    def do(self):
        universe = context.application.model.universe
        scaling = numpy.dot(self.parameters.matrix,
                            numpy.linalg.inv(universe.cell.matrix))
        primitive.SetProperty(
            universe, "cell",
            universe.cell.copy_with(matrix=self.parameters.matrix))

        for child in universe.children:
            if isinstance(child, GLTransformationMixin) and isinstance(
                    child.transformation, Translation):
                new_transformation = child.transformation.copy_with(
                    t=numpy.dot(scaling, child.transformation.t))
                primitive.SetProperty(child, "transformation",
                                      new_transformation)
Exemple #16
0
class RendererConfiguration(Immediate):
    description = "Edit renderer configuration"
    menu_info = MenuInfo("default/_View:viewer",
                         "_Configure renderer",
                         order=(0, 2, 0, 2))
    repeatable = False
    authors = [authors.toon_verstraelen]

    renderer_configuration = FieldsDialogSimple(
        "Renderer configuration",
        fields.group.Table([
            fields.edit.Color(
                label_text="Background color",
                attribute_name="background_color",
            ),
            fields.edit.Color(
                label_text="Periodic box color",
                attribute_name="periodic_box_color",
            ),
            fields.edit.Color(
                label_text="Selection mesh color",
                attribute_name="selection_mesh_color",
            ),
            fields.edit.Color(
                label_text="Fog color",
                attribute_name="fog_color",
            ),
            fields.optional.CheckOptional(
                fields.faulty.Length(
                    label_text="Fog depth",
                    attribute_name="fog_depth",
                    low=0.0,
                    low_inclusive=False,
                )),
        ]), ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
             (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    def do(self):
        class Settings(object):
            pass

        settings = Settings()
        settings.__dict__ = context.application.configuration.settings
        if self.renderer_configuration.run(settings) == gtk.RESPONSE_OK:
            context.application.configuration.settings = settings.__dict__
            context.application.scene.update_render_settings()
Exemple #17
0
    def run(self, max_shell_size, rows, graph):
        self.graph = graph
        self.max_shell_size = max_shell_size

        self.list_store = gtk.ListStore(int, int, *([str]*(max_shell_size+2)))
        for index, row in enumerate(rows):
            row += [""]*(max_shell_size-(len(row)-4))
            self.list_store.append(row)

        response = FieldsDialogSimple.run(self, self)

        self.list_view.set_model(None)
        for column in self.list_view.get_columns():
            self.list_view.remove_column(column)
        del self.graph
        del self.max_shell_size

        return response
Exemple #18
0
    def run(self, max_shell_size, rows, graph):
        self.graph = graph
        self.max_shell_size = max_shell_size

        self.list_store = gtk.ListStore(int, int,
                                        *([str] * (max_shell_size + 2)))
        for index, row in enumerate(rows):
            row += [""] * (max_shell_size - (len(row) - 4))
            self.list_store.append(row)

        response = FieldsDialogSimple.run(self, self)

        self.list_view.set_model(None)
        for column in self.list_view.get_columns():
            self.list_view.remove_column(column)
        del self.graph
        del self.max_shell_size

        return response
Exemple #19
0
class RotateDialog(ImmediateWithMemory):
    description = "Apply rotation (dialog)"
    menu_info = MenuInfo("default/_Object:tools/_Transform:dialogs",
                         "R_otate objects",
                         order=(0, 4, 1, 2, 1, 0))
    authors = [authors.toon_verstraelen]

    parameters_dialog = FieldsDialogSimple(
        "Rotation",
        fields.composed.Rotation(
            label_text="Rotate around axis n",
            attribute_name="rotation",
        ), ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
            (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        node = context.application.cache.node
        if not isinstance(node, GLTransformationMixin): return False
        if not isinstance(node.transformation, Rotation): return False
        if node.get_fixed(): return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.rotation = Rotation.identity()
        return result

    def do(self):
        primitive.Transform(context.application.cache.node,
                            self.parameters.rotation,
                            after=False)
Exemple #20
0
class ReflectionDialog(ImmediateWithMemory):
    description = "Apply reflection transformation"
    menu_info = MenuInfo("default/_Object:tools/_Transform:dialogs",
                         "_Reflection",
                         order=(0, 4, 1, 2, 1, 3))
    authors = [authors.toon_verstraelen]

    parameters_dialog = FieldsDialogSimple(
        "Reflection transformation",
        fields.group.Table(fields=[
            fields.composed.ComposedArray(
                FieldClass=fields.faulty.Length,
                array_name="c.%s",
                suffices=["x", "y", "z"],
                attribute_name="center",
                label_text="Point on the reflection plane.",
                scientific=False,
            ),
            fields.composed.ComposedArray(
                FieldClass=fields.faulty.Float,
                array_name="n.%s",
                suffices=["x", "y", "z"],
                attribute_name="normal",
                label_text="Normal of the reflection plane.",
                scientific=False,
            ),
        ]), ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
             (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        cache = context.application.cache
        if len(cache.translated_nodes) == 0: return False
        if cache.parent_of_translated_nodes is None: return False
        if cache.some_nodes_fixed: return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.center = numpy.zeros(3, float)
        result.normal = numpy.zeros(3, float)
        return result

    def ask_parameters(self):
        cache = context.application.cache
        last = cache.last
        next_to_last = cache.next_to_last
        parent = cache.parent_of_translated_nodes
        Plane = context.application.plugins.get_node("Plane")
        if isinstance(last, Plane):
            f = last.parent.get_frame_relative_to(parent)
            self.parameters.center = f * last.center
            self.parameters.normal = numpy.dot(f.r, last.normal)
        else:
            self.parameters = self.last_parameters()
        if self.parameters_dialog.run(self.parameters) != gtk.RESPONSE_OK:
            self.parameters.clear()

    def do(self):
        transformation = Complete.about_axis(self.parameters.center, numpy.pi,
                                             self.parameters.normal, True)

        for victim in context.application.cache.translated_nodes:
            primitive.Transform(victim, transformation)
Exemple #21
0
class CameraSettings(Immediate):
    description = "Edit camera settings"
    menu_info = MenuInfo("default/_View:viewer",
                         "_Camera settings",
                         order=(0, 2, 0, 1))
    repeatable = False
    authors = [authors.toon_verstraelen]

    viewer_configuration = FieldsDialogSimple(
        "Camera configuration",
        fields.group.HBox(fields=[
            fields.group.Table([
                fields.composed.Translation(
                    label_text="Rotation center",
                    attribute_name="rotation_center",
                ),
                fields.composed.Rotation(
                    label_text="Model rotation",
                    attribute_name="rotation",
                ),
            ]),
            fields.group.Table([
                fields.composed.Translation(
                    label_text="Eye position",
                    attribute_name="eye",
                ),
                fields.faulty.Length(
                    label_text="Window size",
                    attribute_name="window_size",
                    low=0.0,
                    low_inclusive=False,
                ),
                fields.faulty.Length(
                    label_text="Window depth",
                    attribute_name="window_depth",
                    low=0.0,
                    low_inclusive=False,
                ),
                fields.faulty.MeasureEntry(
                    measure="Angle",
                    label_text="Opening angle",
                    attribute_name="opening_angle",
                    low=0,
                    low_inclusive=True,
                    high=0.5 * numpy.pi,
                    high_inclusive=False,
                    show_popup=False,
                ),
            ]),
        ]), ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
             (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection():
        # A) calling ancestor
        if not Immediate.analyze_selection(): return False
        # B) validating and initialising
        if context.application.main is None: return False
        # C) passed all tests:
        return True

    def do(self):
        camera = context.application.camera
        if self.viewer_configuration.run(camera) == gtk.RESPONSE_OK:
            context.application.scene.update_render_settings()
Exemple #22
0
class SaturateHydrogensManual(ImmediateWithMemory):
    description = "Saturate with hydrogens (fixed number)"
    menu_info = MenuInfo("default/_Object:tools/_Molecular:add",
                         "S_aturate with hydrogens (fixed number)",
                         order=(0, 4, 1, 5, 1, 3))
    authors = [authors.toon_verstraelen]

    parameters_dialog = FieldsDialogSimple(
        "Parameters for hydrogen saturation",
        fields.group.Table(fields=[
            fields.faulty.Int(
                attribute_name="num_hydrogens",
                label_text="Number of hydrogens per atom",
                minimum=1,
            ),
            fields.faulty.MeasureEntry(
                attribute_name="valence_angle",
                measure="Angle",
                label_text="Valence angle (X-Y-H)",
                scientific=False,
                low=0.0,
                high=180 * deg,
            ),
        ]), ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
             (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(): return False
        # B) validating
        if len(context.application.cache.nodes) == 0: return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.num_hydrogens = 2
        result.valence_angle = 109.4 * deg
        return result

    def do(self):
        Atom = context.application.plugins.get_node("Atom")
        Bond = context.application.plugins.get_node("Bond")

        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

        for node in context.application.cache.nodes:
            if isinstance(node, Atom):
                add_hydrogens(node)
Exemple #23
0
class SketchOptions(GladeWrapper):

    edit_erase_filter = FieldsDialogSimple(
        "Edit the Erase filter",
        fields.faulty.Expression(
            label_text="Erase filter expression",
            attribute_name="erase_filter",
            show_popup=True,
            history_name="filter",
        ), ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
            (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    def __init__(self):
        GladeWrapper.__init__(self, "plugins/molecular/gui.glade", "wi_sketch",
                              "window")
        self.window.hide()
        self.init_callbacks(self.__class__)
        self.init_proxies([
            "cb_object", "cb_vector", "cb_erase_filter",
            "bu_edit_erase_filter", "la_current", "bu_set_atom", "cb_bondtype",
            "hbox_atoms", "hbox_quickpicks", "hbox_fragments", "la_fragment",
            "cb_fragment"
        ])

        self.erase_filter = Expression("True")
        #Initialize atom number - this can be changed anytime with the edit_atom_number dialog
        self.atom_number = 6

        # Initialize the GUI
        #  1) common parts of the comboboxes
        def render_icon(column, cell, model, iter):
            if model.get_value(iter, 0) == "Fragment":
                cell.set_property(
                    "pixbuf",
                    context.application.plugins.get_node("Atom").icon)
            else:
                cell.set_property(
                    "pixbuf",
                    context.application.plugins.get_node(
                        model.get_value(iter, 0)).icon)

        #  2) fill the objects combo box
        self.object_store = gtk.ListStore(str)
        self.object_store.append(["Atom"])
        self.object_store.append(["Fragment"])
        self.object_store.append(["Point"])
        self.object_store.append(["Sphere"])
        self.object_store.append(["Box"])
        self.cb_object.set_model(self.object_store)

        renderer_pixbuf = gtk.CellRendererPixbuf()
        self.cb_object.pack_start(renderer_pixbuf, expand=False)
        self.cb_object.set_cell_data_func(renderer_pixbuf, render_icon)
        renderer_text = gtk.CellRendererText()
        self.cb_object.pack_start(renderer_text, expand=True)
        self.cb_object.add_attribute(renderer_text, "text", 0)

        self.cb_object.set_active(0)

        #  3) fill the vector combo box
        self.vector_store = gtk.ListStore(str)
        self.vector_store.append(["Bond"])
        self.vector_store.append(["Arrow"])
        self.vector_store.append(["Spring"])
        self.cb_vector.set_model(self.vector_store)

        renderer_pixbuf = gtk.CellRendererPixbuf()
        self.cb_vector.pack_start(renderer_pixbuf, expand=False)
        self.cb_vector.set_cell_data_func(renderer_pixbuf, render_icon)
        renderer_text = gtk.CellRendererText()
        self.cb_vector.pack_start(renderer_text, expand=True)
        self.cb_vector.add_attribute(renderer_text, "text", 0)

        self.cb_vector.set_active(0)

        # 4) fill the bond type combo box
        self.bondtype_store = gtk.ListStore(str, int)
        self.bondtype_store.append(["Single bond", BOND_SINGLE])
        self.bondtype_store.append(["Double bond", BOND_DOUBLE])
        self.bondtype_store.append(["Triple bond", BOND_TRIPLE])
        self.bondtype_store.append(["Hybrid bond", BOND_HYBRID])
        self.bondtype_store.append(["Hydrogen bond", BOND_HYDROGEN])
        self.cb_bondtype.set_model(self.bondtype_store)

        #no icons like the others, just text here
        renderer_text = gtk.CellRendererText()
        self.cb_bondtype.pack_start(renderer_text, expand=True)
        self.cb_bondtype.add_attribute(renderer_text, "text", 0)

        self.cb_bondtype.set_active(0)

        # register quick pick config setting
        config = context.application.configuration
        config.register_setting(
            "sketch_quickpicks",
            [6, 7, 8, 9, 10, 11],
            DialogFieldInfo(
                "Sketch tool", (0, 2),
                fields.faulty.IntegerList(
                    label_text="Quick pick atoms (applies after restart)",
                    attribute_name="sketch_quickpicks",
                )),
        )

        # 5)create the "quick pick" atom buttons
        for index in xrange(len(config.sketch_quickpicks)):
            atomnumber = config.sketch_quickpicks[index]
            bu_element = gtk.Button("")
            bu_element.set_label("%s" % periodic[atomnumber].symbol)
            bu_element.connect("clicked", self.on_bu_element_clicked, index)
            # add to hbox
            self.hbox_quickpicks.pack_start(bu_element)
            bu_element.show()

        # 6)fill the fragment combo box with filenames from share/fragments
        fragment_dir = context.get_share_filename('fragments')
        self.fragment_store = gtk.ListStore(str)
        for filename in sorted(os.listdir(fragment_dir)):
            # Ignore subfolders and files with extension other than cml
            if os.path.isdir(os.path.join(fragment_dir,
                                          filename)) or filename[-3:] != 'cml':
                continue
            self.fragment_store.append([filename[:-4]])
        self.cb_fragment.set_model(self.fragment_store)

        renderer_text = gtk.CellRendererText()
        self.cb_fragment.pack_start(renderer_text, expand=True)
        self.cb_fragment.add_attribute(renderer_text, "text", 0)
        self.cb_fragment.set_active(0)

    @property
    def current_object(self):
        return self.object_store.get_value(self.cb_object.get_active_iter(), 0)

    @property
    def current_fragment(self):
        return self.fragment_store.get_value(
            self.cb_fragment.get_active_iter(), 0)

    def on_window_delete_event(self, window, event):
        self.window.hide()
        return True

    def on_bu_edit_erase_filter_clicked(self, button):
        self.edit_erase_filter.run(self)

    def on_bu_set_atom_clicked(self, button):
        self.edit_atom_number = FieldsDialogSimple(
            "Select atom number",
            fields.edit.Element(attribute_name="atom_number"),
            ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
             (gtk.STOCK_OK, gtk.RESPONSE_OK)))
        self.edit_atom_number.run(self)
        atom_symbol = periodic[self.atom_number].symbol
        self.la_current.set_label("Current: %s " % str(atom_symbol))

    def on_cb_object_changed(self, combo):
        self.hbox_atoms.hide()
        self.la_current.hide()
        self.hbox_fragments.hide()
        if (self.current_object == "Atom"):
            self.hbox_atoms.show()
            self.la_current.show()
        if (self.current_object == "Fragment"):
            self.cb_fragment.show()
            self.hbox_fragments.show()

    def on_bu_element_clicked(self, widget, index):
        self.atom_number = context.application.configuration.sketch_quickpicks[
            index]
        atom_symbol = periodic[self.atom_number].symbol
        self.la_current.set_label("Current: %s" % str(atom_symbol))

    def on_cb_vector_changed(self, combo):
        # When the selected object is an atom, show the extra button.
        if (self.vector_store.get_value(self.cb_vector.get_active_iter(),
                                        0) == "Bond"):
            self.cb_bondtype.show()
        else:
            self.cb_bondtype.hide()

    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 add_new(self, position, parent):
        new = self.get_new(position)

        if self.current_object == "Fragment":
            result = new.children[1]
            primitive.Add(new, parent)
            UnframeAbsolute = context.application.plugins.get_action(
                "UnframeAbsolute")
            UnframeAbsolute([new])
            #return result
        else:
            primitive.Add(new, parent)
            return new

    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 connect(self, gl_object1, gl_object2):
        try:
            new = context.application.plugins.get_node(
                self.vector_store.get_value(
                    self.cb_vector.get_active_iter(),
                    0))(targets=[gl_object1, gl_object2])
        except TargetError:
            return

        if (self.vector_store.get_value(self.cb_vector.get_active_iter(),
                                        0) == "Bond"):
            new.set_bond_type(
                self.bondtype_store.get_value(
                    self.cb_bondtype.get_active_iter(), 1))

        primitive.Add(new,
                      common_parent([gl_object1.parent, gl_object2.parent]))

    def erase_at(self, p, parent):
        for node in context.application.main.drawing_area.iter_hits(
            (p[0] - 2, p[1] - 2, p[0] + 2, p[1] + 2)):
            try:
                match = (node is not None and node != parent
                         and node.is_indirect_child_of(parent)
                         and node.model == context.application.model
                         and (not self.cb_erase_filter.get_active()
                              or self.erase_filter(node)))
            except Exception:
                raise UserError(
                    "An exception occured while evaluating the erase filter expression."
                )
            if match:
                primitive.Delete(node)

    def tool_draw(self, p1, p2):
        drawing_area = context.application.main.drawing_area
        r1 = drawing_area.screen_to_camera(p1)
        r2 = drawing_area.screen_to_camera(p2)
        context.application.vis_backend.tool("line", r1, r2)

    def tool_special(self, p1, p2):
        pass

    def move_special(self, gl_object1, gl_object2, p1, p2):
        pass

    def click_special(self, gl_object):
        pass
Exemple #24
0
class RoundRotation(Immediate):
    description = "Round rotation"
    menu_info = MenuInfo("default/_Object:tools/_Transform:special",
                         "_Round rotation",
                         order=(0, 4, 1, 2, 5, 0))
    authors = [authors.toon_verstraelen]
    axes = {
        "x": numpy.array([1, 0, 0], float),
        "y": numpy.array([0, 1, 0], float),
        "z": numpy.array([0, 0, 1], float)
    }

    select_quaternion = FieldsDialogSimple(
        "Select a rotation",
        fields.edit.List(columns=[("Fit", "cost_function"),
                                  ("Rotation", "name")],
                         attribute_name="quaternion",
                         show_popup=False),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
         (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        cache = context.application.cache
        if len(cache.nodes) == 0 or len(cache.nodes) > 2: return False
        for node in cache.nodes:
            if not isinstance(node, GLTransformationMixin): return False
            if not isinstance(node.transformation, Rotation): return False
            if node.get_fixed(): return False
        # C) passed all tests:
        return True

    def do(self):
        class Record(object):
            def __init__(self, name, quaternion):
                self.name = name
                self.quaternion = quaternion
                self.cost_function = 0.0

        rounded_quaternions = []

        cache = context.application.cache
        if len(cache.nodes) == 1:
            victim = cache.last
            master = None
            factor, selected_quaternion = rotation_matrix_to_quaternion(
                victim.transformation.r)
        elif len(cache.nodes) == 2:
            master = cache.last
            victim = cache.next_to_last
            factor, selected_quaternion = rotation_matrix_to_quaternion(
                victim.get_frame_relative_to(master).r)

        step = 15
        for axis_name, axis in self.axes.iteritems():
            for angle_index in xrange(1, 360 / step):
                angle = angle_index * step
                name = "%s (%s)" % (axis_name, angle)
                rad = angle * numpy.pi / 360
                quaternion = numpy.concatenate(
                    ([numpy.cos(rad)], numpy.sin(rad) * axis), 1)
                rounded_quaternions.append(Record(name, quaternion))

        new_quaternions = [
            Record("Identity", numpy.array([1.0, 0.0, 0.0, 0.0]))
        ]
        for record1 in rounded_quaternions:
            for record2 in rounded_quaternions:
                if record1.name[0] != record2.name[0]:
                    new_quaternions.append(
                        Record(
                            "%s after %s" % (record1.name, record2.name),
                            quaternion_product(record1.quaternion,
                                               record2.quaternion)))

        def filter_out_high_cost(records):
            for record in records:
                #print selected_quaternion, record.quaternion
                cosine = numpy.dot(selected_quaternion, record.quaternion)
                if cosine > 1: cosine = 1
                elif cosine < -1: cosine = -1
                cost_function = int(numpy.arccos(cosine) * 180.0 / numpy.pi)
                if cost_function < 10:
                    record.cost_function = cost_function
                else:
                    record.quaternion = None

            return filter(lambda record: record.quaternion is not None,
                          records)

        new_quaternions = filter_out_high_cost(new_quaternions)

        for index1, record1 in enumerate(new_quaternions):
            if record1.quaternion is not None:
                for record2 in new_quaternions[:index1]:
                    if record2.quaternion is not None:
                        if 1 - numpy.dot(record1.quaternion,
                                         record2.quaternion) < 1e-3:
                            record2.quaternion = None
                for record2 in rounded_quaternions:
                    if 1 - numpy.dot(record1.quaternion,
                                     record2.quaternion) < 1e-3:
                        record1.quaternion = None
                        break

        new_quaternions = filter(lambda record: record.quaternion is not None,
                                 new_quaternions)

        rounded_quaternions = filter_out_high_cost(rounded_quaternions)

        rounded_quaternions.extend(new_quaternions)

        if len(rounded_quaternions) == 0:
            raise UserError("No similar rounded rotations found.")

        rounded_quaternions.sort(key=(lambda x: x.cost_function))

        self.select_quaternion.main_field.records = rounded_quaternions
        user_record = Record("", rounded_quaternions[0].quaternion)
        if self.select_quaternion.run(user_record) != gtk.RESPONSE_OK:
            raise CancelException

        if user_record.quaternion is not None:
            if len(cache.nodes) == 1:
                r = factor * quaternion_to_rotation_matrix(
                    user_record.quaternion)
                new_transformation = victim.transformation.copy_with(r=r)
                primitive.SetProperty(victim, "transformation",
                                      new_transformation)
            elif len(cache.nodes) == 2:
                r = numpy.dot(
                    master.get_frame_relative_to(victim).r,
                    factor *
                    quaternion_to_rotation_matrix(user_record.quaternion),
                )
                old_transformation = victim.transformation.copy_with(r=r)
                primitive.SetProperty(victim,
                                      "transformation",
                                      old_transformation,
                                      done=True)
Exemple #25
0
class SuperCell(ImmediateWithMemory):
    description = "Convert the unit cell to larger unit cell"
    menu_info = MenuInfo("default/_Object:tools/_Unit Cell:default",
                         "_Super cell",
                         order=(0, 4, 1, 4, 0, 1))
    authors = [authors.toon_verstraelen]
    store_last_parameters = False

    parameters_dialog = FieldsDialogSimple(
        "Super cell",
        fields.group.Table(
            fields=[
                fields.faulty.Int(
                    attribute_name="repetitions_%s" % ridge.lower(),
                    label_text=ridge,
                    minimum=1,
                ) for ridge in ["a", "b", "c"]
            ],
            label_text="The number of repetitions along each active axis."),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
         (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        universe = context.application.model.universe
        if sum(universe.cell.active) == 0: return False
        if hasattr(parameters,
                   "repetitions_a") and not universe.cell.active[0]:
            return False
        if hasattr(parameters,
                   "repetitions_b") and not universe.cell.active[1]:
            return False
        if hasattr(parameters,
                   "repetitions_c") and not universe.cell.active[2]:
            return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        universe = context.application.model.universe
        if universe.cell.active[0]:
            result.repetitions_a = universe.repetitions[0]
        if universe.cell.active[1]:
            result.repetitions_b = universe.repetitions[1]
        if universe.cell.active[2]:
            result.repetitions_c = universe.repetitions[2]
        return result

    def do(self):
        # create the repetitions vector
        repetitions = []

        if hasattr(self.parameters, "repetitions_a"):
            repetitions.append(self.parameters.repetitions_a)
        else:
            repetitions.append(1)

        if hasattr(self.parameters, "repetitions_b"):
            repetitions.append(self.parameters.repetitions_b)
        else:
            repetitions.append(1)

        if hasattr(self.parameters, "repetitions_c"):
            repetitions.append(self.parameters.repetitions_c)
        else:
            repetitions.append(1)

        repetitions = numpy.array(repetitions, int)

        # serialize the positioned children
        universe = context.application.model.universe

        positioned = [
            node for node in universe.children
            if (isinstance(node, GLTransformationMixin)
                and isinstance(node.transformation, Translation))
        ]
        if len(positioned) == 0: return

        serialized = StringIO.StringIO()
        dump_to_file(serialized, positioned)

        # create the replica's

        # replicate the positioned objects
        new_children = {}
        for cell_index in iter_all_positions(repetitions):
            cell_index = numpy.array(cell_index)
            cell_hash = tuple(cell_index)
            serialized.seek(0)
            nodes = load_from_file(serialized)
            new_children[cell_hash] = nodes
            for node in nodes:
                t = node.transformation.t + numpy.dot(universe.cell.matrix,
                                                      cell_index)
                new_transformation = node.transformation.copy_with(t=t)
                node.set_transformation(new_transformation)

        # forget about serialized stuff
        serialized.close()
        del serialized

        new_connectors = []
        # replicate the objects that connect these positioned objects
        for cell_index in iter_all_positions(repetitions):
            cell_index = numpy.array(cell_index)
            cell_hash = tuple(cell_index)
            for connector in universe.children:
                # Only applicable to ReferentMixin with only SpatialReference
                # children
                if not isinstance(connector, ReferentMixin):
                    continue
                skip = False
                for reference in connector.children:
                    if not isinstance(reference, SpatialReference):
                        skip = True
                        break
                if skip:
                    continue

                # first locate the new first target for this cell_index
                first_target_orig = connector.children[0].target
                first_target_index = positioned.index(first_target_orig)
                first_target = new_children[cell_hash][first_target_index]
                assert first_target is not None
                new_targets = [first_target]

                for reference in connector.children[1:]:
                    # then find the other new targets, taking into account
                    # periodicity
                    other_target_orig = reference.target
                    shortest_vector = universe.shortest_vector(
                        (other_target_orig.transformation.t -
                         first_target_orig.transformation.t))
                    translation = first_target.transformation.t + shortest_vector
                    other_target_pos = translation
                    other_cell_index = numpy.floor(
                        universe.cell.to_fractional(other_target_pos)).astype(
                            int)
                    other_cell_index %= repetitions
                    other_cell_hash = tuple(other_cell_index)
                    other_target_index = positioned.index(other_target_orig)
                    other_cell_children = new_children.get(other_cell_hash)
                    assert other_cell_children is not None
                    other_target = other_cell_children[other_target_index]
                    assert other_target is not None
                    new_targets.append(other_target)

                state = connector.__getstate__()
                state["targets"] = new_targets
                new_connectors.append(connector.__class__(**state))

        # remove the existing nodes
        while len(universe.children) > 0:
            primitive.Delete(universe.children[0])
        del positioned

        # multiply the cell matrix and reset the number of repetitions
        new_matrix = universe.cell * repetitions
        primitive.SetProperty(universe, "cell", new_matrix)
        primitive.SetProperty(universe, "repetitions",
                              numpy.array([1, 1, 1], int))

        # add the new nodes
        for nodes in new_children.itervalues():
            for node in nodes:
                primitive.Add(node, universe)

        for connector in new_connectors:
            primitive.Add(connector, universe)
Exemple #26
0
class ScanForConnections(ImmediateWithMemory):
    description = "Scan for connections"
    menu_info = MenuInfo("default/_Object:tools/_Builder:conscan",
                         "_Scan for connections",
                         order=(0, 4, 1, 6, 1, 0))
    authors = [authors.toon_verstraelen]

    parameters_dialog = FieldsDialogSimple(
        "Connection scanner parameters",
        fields.group.Notebook([
            (
                "Geometry1",
                fields.group.Table(fields=[
                    ConnectionPointDescription(
                        label_text="Connecting points",
                        attribute_name="connect_description1",
                        history_name="conscan_description",
                    ),
                    ConnectionPointDescription(
                        label_text="Repulsive points",
                        attribute_name="repulse_description1",
                        history_name="conscan_description",
                    ),
                ],
                                   cols=2),
            ),
            (
                "Geometry2",
                fields.group.Table(fields=[
                    ConnectionPointDescription(
                        label_text="Connecting points",
                        attribute_name="connect_description2",
                        history_name="conscan_description",
                    ),
                    ConnectionPointDescription(
                        label_text="Repulsive points",
                        attribute_name="repulse_description2",
                        history_name="conscan_description",
                    ),
                ],
                                   cols=2),
            ),
            (
                "Parameters",
                fields.group.Table(fields=[
                    fields.faulty.Length(
                        label_text="Action radius",
                        attribute_name="action_radius",
                        low=0.0,
                        low_inclusive=False,
                    ),
                    fields.faulty.Length(
                        label_text="Distance tolerance",
                        attribute_name="hit_tolerance",
                        low=0.0,
                        low_inclusive=False,
                    ),
                    fields.group.Table(fields=[
                        fields.optional.RadioOptional(
                            slave=fields.group.Table(fields=[
                                fields.edit.CheckButton(
                                    label_text="Allow inversion rotations",
                                    attribute_name="allow_inversions",
                                ),
                                fields.faulty.Length(
                                    label_text="Minimum triangle size",
                                    attribute_name="minimum_triangle_size",
                                    low=0.0,
                                    low_inclusive=False,
                                ),
                            ],
                                                     label_text=
                                                     "Allow free rotations")),
                        fields.optional.RadioOptional(
                            slave=fields.group.Table(fields=[
                                fields.composed.Rotation(
                                    label_text=
                                    "Relative rotation of the two structures",
                                    attribute_name="rotation2",
                                ),
                            ],
                                                     label_text=
                                                     "Use a fixed rotation")),
                    ],
                                       cols=2),
                ]),
            )
        ]),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
         (gtk.STOCK_OK, gtk.RESPONSE_OK)),
    )

    triangle_report_dialog = ConscanReportDialog([
        ("calc_env", "Calculating environments"),
        ("comp_env", "Comparing environments"),
        ("calc_trans", "Calculating transformations"),
        ("mirror", "Adding inversions"),
        ("eval_con", "Evaluating connections"),
        ("elim_dup", "Eliminating duplicates"),
        ("send_con", "Receiving solutions"),
    ])

    pair_report_dialog = ConscanReportDialog([
        ("calc_env", "Calculating environments"),
        ("comp_env", "Comparing environments"),
        ("calc_trans", "Calculating transformations"),
        ("eval_con", "Evaluating connections"),
        ("elim_dup", "Eliminating duplicates"),
        ("send_con", "Receiving solutions"),
    ])

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        cache = context.application.cache
        if len(cache.nodes) == 0 or len(cache.nodes) > 2: return False
        for Class in cache.classes:
            if not issubclass(Class, GLFrameBase): return False
        if len(cache.nodes) == 2 and not isinstance(cache.parent,
                                                    GLContainerMixin):
            return False
        # C) passed all tests:
        return True

    @classmethod
    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 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

    def do(self):
        cache = context.application.cache

        geometry_nodes = [[], []]

        def get_parameters(node, point_type, geometry_index, filter_expression,
                           radius_expression):
            template = "An exception occured in the %%s expression\nfor the %s points of geometry %i." % (
                point_type, geometry_index + 1)
            try:
                is_type = filter_expression(node)
            except Exception:
                raise UserError(template % "filter")
            if is_type:
                try:
                    radius = radius_expression(node)
                except Exception:
                    raise UserError(template % "radius")
                geometry_nodes[geometry_index].append(node)
                return True, radius
            else:
                return False, None

        def read_geometry(frame, geometry_index, connect_description,
                          repulse_description):
            coordinates = []
            connect_masks = []
            radii = []
            for child in frame.children:
                if isinstance(child, GLTransformationMixin) and \
                   isinstance(child.transformation, Translation):
                    is_connect, radius = get_parameters(
                        child, "connecting", geometry_index,
                        *connect_description)
                    if is_connect:
                        coordinates.append(child.transformation.t)
                        connect_masks.append(True)
                        radii.append(radius)
                    else:
                        is_repulse, radius = get_parameters(
                            child, "repulsive", geometry_index,
                            *repulse_description)
                        if is_repulse:
                            coordinates.append(child.transformation.t)
                            connect_masks.append(False)
                            radii.append(radius)
            return Geometry(
                numpy.array(coordinates, float),
                numpy.array(connect_masks, bool),
                numpy.array(radii, float),
            )

        inp = {}
        inp["geometry1"] = read_geometry(cache.nodes[0], 0,
                                         self.parameters.connect_description1,
                                         self.parameters.repulse_description1)
        if len(cache.nodes) == 2:
            inp["geometry2"] = read_geometry(
                cache.nodes[1], 1, self.parameters.connect_description2,
                self.parameters.repulse_description2)
        else:
            inp["geometry2"] = None
        inp["action_radius"] = self.parameters.action_radius
        inp["hit_tolerance"] = self.parameters.hit_tolerance
        if not isinstance(self.parameters.allow_inversions, Undefined):
            inp["allow_rotations"] = True
            inp["allow_inversions"] = self.parameters.allow_inversions
            inp["minimum_triangle_area"] = self.parameters.minimum_triangle_size**2
        else:
            inp["allow_rotations"] = False
            if isinstance(self.parameters.rotation2, Undefined):
                inp["rotation2"] = Rotation.identity()
            else:
                inp["rotation2"] = self.parameters.rotation2

        if inp["allow_rotations"]:
            connections = self.triangle_report_dialog.run(inp)
        else:
            connections = self.pair_report_dialog.run(inp)

        if connections is not None and len(connections) > 0:
            if len(cache.nodes) == 1:
                frame1 = cache.nodes[0]
                Duplicate = context.application.plugins.get_action("Duplicate")
                Duplicate()
                frame2 = cache.nodes[0]
                geometry_nodes[1] = geometry_nodes[0]
            else:
                frame1, frame2 = cache.nodes

            conscan_results = ConscanResults(
                targets=[frame1, frame2],
                connections=[(
                    float(connection.quality),
                    connection.transformation,
                    [(geometry_nodes[0][first].get_index(),
                      geometry_nodes[1][second].get_index())
                     for first, second in connection.pairs],
                    [(geometry_nodes[0][second].get_index(),
                      geometry_nodes[1][first].get_index())
                     for first, second in connection.pairs
                     if connection.invertible],
                ) for connection in connections],
            )
            primitive.Add(conscan_results, context.application.model.folder)
Exemple #27
0
class CreateTube(ImmediateWithMemory):
    description = "Create Tube"
    menu_info = MenuInfo("default/_Object:tools/_Builder:generate",
                         "_Create tube",
                         order=(0, 4, 1, 6, 1, 0))
    authors = [authors.toon_verstraelen]

    @staticmethod
    def analyze_selection(parameters=None):
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        if context.application.model.universe.cell.active.sum() != 2:
            return False
        return True

    parameters_dialog = FieldsDialogSimple(
        "Tube parameters",
        fields.group.Table(fields=[
            fields.faulty.Int(
                label_text="n",
                attribute_name="n",
                minimum=1,
                maximum=100,
            ),
            fields.faulty.Int(
                label_text="m",
                attribute_name="m",
                minimum=0,
                maximum=100,
            ),
            fields.edit.CheckButton(
                label_text="Flat",
                attribute_name="flat",
            ),
            fields.optional.RadioOptional(
                fields.group.Table(label_text="Periodic (along tube axis)",
                                   fields=[
                                       fields.faulty.Length(
                                           label_text="Maximum tube length",
                                           attribute_name="max_length",
                                           low=0.0,
                                           low_inclusive=False,
                                       ),
                                       fields.faulty.Length(
                                           label_text="Maximum mismatch",
                                           attribute_name="max_error",
                                           low=0.0,
                                           low_inclusive=False,
                                       ),
                                   ])),
            fields.optional.RadioOptional(
                fields.group.Table(label_text="Not periodic",
                                   fields=[
                                       fields.faulty.Length(
                                           label_text="Tube length",
                                           attribute_name="tube_length",
                                           low=0.0,
                                           low_inclusive=False,
                                       ),
                                   ])),
        ]),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
         (gtk.STOCK_OK, gtk.RESPONSE_OK)),
    )

    @classmethod
    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 do(self):
        # the indices (n,m) that define the tube, see e.g. the wikipedia page
        # about nanotubes for the interpretation of these indices:
        # http://en.wikipedia.org/wiki/Carbon_nanotube
        n = self.parameters.n
        m = self.parameters.m

        periodic_tube = isinstance(self.parameters.tube_length, Undefined)

        universe = context.application.model.universe

        def define_flat():
            "Reads and converts the unit cell vectors from the current model."
            # some parts of the algorithm have been arranged sub functions like
            # these, to reduce the number of local variables in self.do. This
            # should also clarify the code.
            active, inactive = universe.cell.active_inactive
            lengths, angles = universe.cell.parameters
            a = lengths[active[0]]
            b = lengths[active[1]]
            theta = angles[inactive[0]]
            return (numpy.array([a, 0], float),
                    numpy.array([b * numpy.cos(theta), b * numpy.sin(theta)],
                                float))

        flat_a, flat_b = define_flat()

        def create_pattern():
            "Read the atom positions and transform them to the flat coordinates"
            active, inactive = universe.cell.active_inactive
            a = universe.cell.matrix[:, active[0]]
            b = universe.cell.matrix[:, active[1]]
            c = numpy.cross(a, b)
            tmp_cell = UnitCell(numpy.array([a, b, c]).transpose())
            rotation = tmp_cell.alignment_a

            return [(atom.number, rotation * atom.get_absolute_frame().t)
                    for atom in iter_atoms([universe])]

        pattern = create_pattern()

        def define_big_periodic():
            "Based on (n,m) calculate the size of the periodic sheet (that will be folded into a tube)."
            big_a = n * flat_a - m * flat_b
            norm_a = numpy.linalg.norm(big_a)
            radius = norm_a / (2 * numpy.pi)
            big_x = big_a / norm_a
            big_y = numpy.array([-big_x[1], big_x[0]], float)

            big_b = None
            stack_vector = flat_b - flat_a * numpy.dot(
                big_x, flat_b) / numpy.dot(big_x, flat_a)
            stack_length = numpy.linalg.norm(stack_vector)
            nominator = numpy.linalg.norm(stack_vector - flat_b)
            denominator = numpy.linalg.norm(flat_a)
            fraction = nominator / denominator
            stack_size = 1
            while True:
                repeat = fraction * stack_size
                if stack_length * stack_size > self.parameters.max_length:
                    break
                if abs(repeat - round(repeat)
                       ) * denominator < self.parameters.max_error:
                    big_b = stack_vector * stack_size
                    break
                stack_size += 1
            if big_b is None:
                raise UserError(
                    "Could not create a periodic tube shorter than the given maximum length."
                )
            rotation = numpy.array([big_x, big_y], float)
            return big_a, big_b, rotation, stack_vector, stack_size, radius

        def define_big_not_periodic():
            "Based on (n,m) calculate the size of the non-periodic sheet (that will be folded into a tube)."
            big_a = n * flat_a - m * flat_b
            norm_a = numpy.linalg.norm(big_a)
            radius = norm_a / (2 * numpy.pi)
            big_x = big_a / norm_a
            big_y = numpy.array([-big_x[1], big_x[0]], float)

            stack_vector = flat_b - flat_a * numpy.dot(
                big_x, flat_b) / numpy.dot(big_x, flat_a)
            stack_length = numpy.linalg.norm(stack_vector)
            stack_size = int(self.parameters.tube_length / stack_length)
            big_b = stack_vector * stack_size
            rotation = numpy.array([big_x, big_y], float)
            return big_a, big_b, rotation, stack_vector, stack_size, radius

        if periodic_tube:
            big_a, big_b, rotation, stack_vector, stack_size, radius = define_big_periodic(
            )
        else:
            big_a, big_b, rotation, stack_vector, stack_size, radius = define_big_not_periodic(
            )

        def iter_translations():
            "Yields the indices of the periodic images that are part of the tube."
            to_fractional = numpy.linalg.inv(
                numpy.array([big_a, big_b]).transpose())
            col_len = int(
                numpy.linalg.norm(big_a + m * stack_vector) /
                numpy.linalg.norm(flat_a)) + 4
            shift = numpy.dot(stack_vector - flat_b,
                              flat_a) / numpy.linalg.norm(flat_a)**2
            for row in xrange(-m - 1, stack_size + 1):
                col_start = int(numpy.floor(row * shift)) - 1
                for col in xrange(col_start, col_start + col_len):
                    p = col * flat_a + row * flat_b
                    i = numpy.dot(to_fractional, p)
                    if (i >= 0).all() and (i < 1 - 1e-15).all():
                        yield p
                    #yield p, (i >= 0).all() and (i < 1).all()

        def iter_pattern():
            for number, coordinate in pattern:
                yield number, coordinate.copy()

        # first delete everything the universe:
        while len(universe.children) > 0:
            primitive.Delete(universe.children[0])

        # add the new atoms
        Atom = context.application.plugins.get_node("Atom")
        if self.parameters.flat:
            rot_a = numpy.dot(rotation, big_a)
            rot_b = numpy.dot(rotation, big_b)
            big_matrix = numpy.array([
                [rot_a[0], rot_b[0], 0],
                [rot_a[1], rot_b[1], 0],
                [0, 0, 10 * angstrom],
            ], float)
            big_cell = UnitCell(
                big_matrix, numpy.array([True, periodic_tube, False], bool))
            primitive.SetProperty(universe, "cell", big_cell)
            for p in iter_translations():
                for number, coordinate in iter_pattern():
                    coordinate[:2] += p
                    coordinate[:2] = numpy.dot(rotation, coordinate[:2])
                    translation = Translation(coordinate)
                    primitive.Add(
                        Atom(number=number, transformation=translation),
                        universe)
        else:
            tube_length = numpy.linalg.norm(big_b)
            big_matrix = numpy.diag([radius * 2, radius * 2, tube_length])
            big_cell = UnitCell(
                big_matrix, numpy.array([False, False, periodic_tube], bool))
            primitive.SetProperty(universe, "cell", big_cell)
            for p in iter_translations():
                for number, coordinate in iter_pattern():
                    coordinate[:2] += p
                    coordinate[:2] = numpy.dot(rotation, coordinate[:2])
                    translation = Translation(
                        numpy.array([
                            (radius + coordinate[2]) *
                            numpy.cos(coordinate[0] / radius),
                            (radius + coordinate[2]) *
                            numpy.sin(coordinate[0] / radius),
                            coordinate[1],
                        ]))
                    primitive.Add(
                        Atom(number=number, transformation=translation),
                        universe)
Exemple #28
0
class DistributionDihedralAngles(ImmediateWithMemory):
    description = "Distribution of dihedral angles"
    menu_info = MenuInfo("default/_Object:tools/_Molecular:dist",
                         "Distribution of _dihedral angles",
                         order=(0, 4, 1, 5, 3, 2))
    authors = [authors.toon_verstraelen]
    required_modules = ["pylab", "matplotlib"]

    parameters_dialog = FieldsDialogSimple(
        "Dihedral angle distribution parameters",
        fields.group.Table(fields=[
            fields.faulty.Expression(
                label_text="Filter expression: atom 1",
                attribute_name="filter_atom1",
                history_name="filter_atom",
                width=250,
                height=60,
            ),
            fields.faulty.Expression(
                label_text="Filter expression: bond 1-2",
                attribute_name="filter_bond12",
                history_name="filter_bond",
                width=250,
                height=60,
            ),
            fields.faulty.Expression(
                label_text="Filter expression: atom 2",
                attribute_name="filter_atom2",
                history_name="filter_atom",
                width=250,
                height=60,
            ),
            fields.faulty.Expression(
                label_text="Filter expression: bond 2-3",
                attribute_name="filter_bond23",
                history_name="filter_bond",
                width=250,
                height=60,
            ),
            fields.faulty.Expression(
                label_text="Filter expression: atom 3",
                attribute_name="filter_atom3",
                history_name="filter_atom",
                width=250,
                height=60,
            ),
            fields.faulty.Expression(
                label_text="Filter expression: bond 3-4",
                attribute_name="filter_bond34",
                history_name="filter_bond",
                width=250,
                height=60,
            ),
            fields.faulty.Expression(
                label_text="Filter expression: atom 4",
                attribute_name="filter_atom4",
                history_name="filter_atom",
                width=250,
                height=60,
            ),
        ],
                           cols=2),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
         (gtk.STOCK_OK, gtk.RESPONSE_OK)),
    )

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        cache = context.application.cache
        if len(cache.nodes) == 0: return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.filter_atom1 = Expression()
        result.filter_bond12 = Expression()
        result.filter_atom2 = Expression()
        result.filter_bond23 = Expression()
        result.filter_atom3 = Expression()
        result.filter_bond34 = Expression()
        result.filter_atom4 = Expression()
        return result

    def do(self):
        for key, val in self.parameters.__dict__.iteritems():
            if isinstance(val, Expression):
                val.compile_as("<%s>" % key)
                val.variables = (key[7:11], )

        parent = context.application.cache.common_parent
        if parent is None:
            parent = context.application.model.universe
        angles = []
        graph = create_molecular_graph(context.application.cache.nodes)

        match_definition = DihedralAnglePattern(criteria_sets=[
            CriteriaSet(
                thing_criteria={
                    0: IndexToAtoms(self.parameters.filter_atom1),
                    1: IndexToAtoms(self.parameters.filter_atom2),
                    2: IndexToAtoms(self.parameters.filter_atom3),
                    3: IndexToAtoms(self.parameters.filter_atom4),
                },
                relation_criteria={
                    0: IndexToBonds(self.parameters.filter_bond12),
                    1: IndexToBonds(self.parameters.filter_bond23),
                    2: IndexToBonds(self.parameters.filter_bond34),
                },
            )
        ], )
        try:
            atoms = graph.molecule.atoms
            match_generator = GraphSearch(match_definition)
            for match in match_generator(graph):
                point1 = atoms[match.forward[0]].get_absolute_frame().t
                point2 = atoms[match.forward[1]].get_absolute_frame().t
                point3 = atoms[match.forward[2]].get_absolute_frame().t
                point4 = atoms[match.forward[3]].get_absolute_frame().t
                normal1 = numpy.cross(parent.shortest_vector(point2 - point1),
                                      parent.shortest_vector(point2 - point3))
                normal2 = numpy.cross(parent.shortest_vector(point3 - point4),
                                      parent.shortest_vector(point3 - point2))
                if numpy.linalg.norm(normal1) > 1e-8 and \
                    numpy.linalg.norm(normal2) > 1e-8:
                    angles.append(angle(normal1, normal2))
        except:
            raise UserError(
                "An error occured while sampling the dihedral angles.",
                "If this is an error in one of the filter expressions,\n" +
                "one should see the expression mentioned below as <filter_...>.\n\n"
            )

        comments = [
            "atom 1 filter expression: %s" % self.parameters.filter_atom1.code,
            "bond 1-2 filter expression: %s" %
            self.parameters.filter_bond12.code,
            "atom 2 filter expression: %s" % self.parameters.filter_atom2.code,
            "bond 2-3 filter expression: %s" %
            self.parameters.filter_bond23.code,
            "atom 3 filter expression: %s" % self.parameters.filter_atom3.code,
            "bond 3-4 filter expression: %s" %
            self.parameters.filter_bond34.code,
            "atom 4 filter expression: %s" % self.parameters.filter_atom4.code,
        ]

        if len(angles) > 0:
            distribution_dialog = DistributionDialog()
            distribution_dialog.run(numpy.array(angles), "Angle",
                                    "Dihedral angle", comments)
        else:
            raise UserError("No dihedral angles match the given criteria.")
Exemple #29
0
class SketchOptions(GladeWrapper):

    edit_erase_filter = FieldsDialogSimple(
        "Edit the Erase filter",
        fields.faulty.Expression(
            label_text="Erase filter expression",
            attribute_name="erase_filter",
            show_popup=True,
            history_name="filter",
        ),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK))
    )

    def __init__(self):
        GladeWrapper.__init__(self, "plugins/molecular/gui.glade", "wi_sketch", "window")
        self.window.hide()
        self.init_callbacks(self.__class__)
        self.init_proxies([
            "cb_object",
            "cb_vector",
            "cb_erase_filter",
            "bu_edit_erase_filter",
            "la_current",
            "bu_set_atom",
            "cb_bondtype",
            "hbox_atoms",
            "hbox_quickpicks",
            "hbox_fragments",
            "la_fragment",
            "cb_fragment"
        ])

        self.erase_filter = Expression("True")
        #Initialize atom number - this can be changed anytime with the edit_atom_number dialog
        self.atom_number = 6;

        # Initialize the GUI
        #  1) common parts of the comboboxes
        def render_icon(column, cell, model, iter):
            cell.set_property(
                "pixbuf",
                context.application.plugins.get_node(model.get_value(iter, 0)).icon
            )

        #  2) fill the objects combo box
        self.object_store = gtk.ListStore(str)
        self.object_store.append(["Atom"])
        self.object_store.append(["Fragment"])
        self.object_store.append(["Point"])
        self.object_store.append(["Sphere"])
        self.object_store.append(["Box"])
        self.cb_object.set_model(self.object_store)

        renderer_pixbuf = gtk.CellRendererPixbuf()
        self.cb_object.pack_start(renderer_pixbuf, expand=False)
        self.cb_object.set_cell_data_func(renderer_pixbuf, render_icon)
        renderer_text = gtk.CellRendererText()
        self.cb_object.pack_start(renderer_text, expand=True)
        self.cb_object.add_attribute(renderer_text, "text", 0)

        self.cb_object.set_active(0)

        #  3) fill the vector combo box
        self.vector_store = gtk.ListStore(str)
        self.vector_store.append(["Bond"])
        self.vector_store.append(["Arrow"])
        self.vector_store.append(["Spring"])
        self.cb_vector.set_model(self.vector_store)

        renderer_pixbuf = gtk.CellRendererPixbuf()
        self.cb_vector.pack_start(renderer_pixbuf, expand=False)
        self.cb_vector.set_cell_data_func(renderer_pixbuf, render_icon)
        renderer_text = gtk.CellRendererText()
        self.cb_vector.pack_start(renderer_text, expand=True)
        self.cb_vector.add_attribute(renderer_text, "text", 0)

        self.cb_vector.set_active(0)

        # 4) fill the bond type combo box
        self.bondtype_store = gtk.ListStore(str,int)
        self.bondtype_store.append(["Single bond",BOND_SINGLE])
        self.bondtype_store.append(["Double bond",BOND_DOUBLE])
        self.bondtype_store.append(["Triple bond",BOND_TRIPLE])
        self.bondtype_store.append(["Hybrid bond",BOND_HYBRID])
        self.bondtype_store.append(["Hydrogen bond",BOND_HYDROGEN])
        self.cb_bondtype.set_model(self.bondtype_store)

        #no icons like the others, just text here
        renderer_text = gtk.CellRendererText()
        self.cb_bondtype.pack_start(renderer_text, expand=True)
        self.cb_bondtype.add_attribute(renderer_text, "text", 0)

        self.cb_bondtype.set_active(0)

        # register quick pick config setting
        config = context.application.configuration
        config.register_setting(
            "sketch_quickpicks",
            [6,7,8,9,10,11],
        )
        #WOUTER I messed up this setting and now Zeobuilder keeps crashing cause it was set to empty
        config.sketch_quickpicks = [6,7,8,9,10,11]

        # 5)create the "quick pick" atom buttons
        for index in xrange(len(config.sketch_quickpicks)):
            atomnumber = config.sketch_quickpicks[index]
            bu_element = gtk.Button("")
            bu_element.set_label("%s" % periodic[atomnumber].symbol)
            bu_element.connect("clicked", self.on_bu_element_clicked, index)
            # add to hbox
            self.hbox_quickpicks.pack_start(bu_element)
            bu_element.show()

        # 6)fill the fragment combo box with filenames from share/fragments
        fragmentdir = context.get_share_filename('fragments')
        self.fragment_store = gtk.ListStore(str)
        for filename in os.listdir (fragmentdir):
            # Ignore subfolders and files with extension other than cml
            if os.path.isdir (os.path.join (fragmentdir, filename)) or filename[-3:] != 'cml':
                continue
            self.fragment_store.append([filename[:-4]])
        self.cb_fragment.set_model(self.fragment_store)

        renderer_text = gtk.CellRendererText()
        self.cb_fragment.pack_start(renderer_text, expand=True)
        self.cb_fragment.add_attribute(renderer_text, "text", 0)
        self.cb_fragment.set_active(0)

        self.doing_fragment = False #at init we do atoms :)

    def on_window_delete_event(self, window, event):
        return True

    def on_bu_edit_erase_filter_clicked(self, button):
        self.edit_erase_filter.run(self)

    def on_bu_set_atom_clicked(self, button):
        self.edit_atom_number = FieldsDialogSimple(
            "Select atom number",
            fields.edit.Element(attribute_name="atom_number"),
            ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK))
        )
        self.edit_atom_number.run(self)
        atom_symbol = periodic[self.atom_number].symbol
        self.la_current.set_label("Current: %s " % str(atom_symbol))

    def on_cb_object_changed(self, combo):
        # When the selected object is an atom, show the extra button.
        self.hbox_atoms.hide()
        self.la_current.hide()
        self.hbox_fragments.hide()
        self.doing_fragment = False
        if(self.object_store.get_value(self.cb_object.get_active_iter(),0)=="Atom"):
            self.hbox_atoms.show()
            self.la_current.show()
        if(self.object_store.get_value(self.cb_object.get_active_iter(),0)=="Fragment"):
            self.doing_fragment = True
            self.cb_fragment.show()
            #self.la_fragment.show()
            self.hbox_fragments.show()

    def on_bu_element_clicked(self, widget, index):
        self.atom_number = context.application.configuration.sketch_quickpicks[index]
        atom_symbol = periodic[self.atom_number].symbol
        self.la_current.set_label("Current: %s" % str(atom_symbol))

    def on_cb_vector_changed(self, combo):
        # When the selected object is an atom, show the extra button.
        if (self.vector_store.get_value(self.cb_vector.get_active_iter(),0)=="Bond"):
            self.cb_bondtype.show()
        else:
            self.cb_bondtype.hide()

    def get_new(self,position):
        object_type = self.object_store.get_value(self.cb_object.get_active_iter(), 0)
        print object_type
        if object_type == "Fragment":   #if it's a 'Fragment', set fragment name to current item in combo box
            fragment = context.application.plugins.get_node("Fragment")(self.fragment_store.get_value(self.cb_fragment.get_active_iter(),0))
            fragment.set_name(self.fragment_store.get_value(self.cb_fragment.get_active_iter(),0))
            new = fragment.get_in_frame(position)

        else:
            new = context.application.plugins.get_node(object_type)()

            if object_type == "Atom":  #if it's an 'Atom', set the atom number to the current atom number?
                new.set_number(self.atom_number)
                new.set_name(periodic[self.atom_number].symbol)

            new.transformation.t[:] = position

        return new

    def add_new(self, position, parent):
        print "position:"
        print position

        new = self.get_new(position)
        print new
        primitive.Add(new, parent)


    def replace(self, gl_object):
        print gl_object

        if not gl_object.get_fixed():
            if self.doing_fragment:
                print "replacing atom with fragment"
                position = gl_object.transformation.t
                parent = gl_object.parent
                new = self.get_new(position)
                new.addToModel(position,parent)
                primitive.Delete(gl_object)
            else:
                new = self.get_new(gl_object.transformation.t)
                # old way: new.transformation.t[:] =
                for reference in gl_object.references[::-1]:
                    if not reference.check_target(new):
                        return
                parent = gl_object.parent
                primitive.Add(new, parent)
                for reference in gl_object.references[::-1]:
                    reference.set_target(new)
                primitive.Delete(gl_object)

    def connect(self, gl_object1, gl_object2):
        print "connecting:"
        print gl_object1,gl_object2
        try:
            new = context.application.plugins.get_node(
                self.vector_store.get_value(self.cb_vector.get_active_iter(), 0)
            )(targets=[gl_object1, gl_object2])
        except TargetError:
            return

        if(self.vector_store.get_value(self.cb_vector.get_active_iter(), 0)=="Bond"):
            new.set_bond_type(self.bondtype_store.get_value(self.cb_bondtype.get_active_iter(),1))

        primitive.Add(new, common_parent([gl_object1.parent, gl_object2.parent]))

    def erase_at(self, p, parent):
        for node in context.application.main.drawing_area.yield_hits((p[0]-2, p[1]-2, p[0]+2, p[1]+2)):
            try:
                match = (
                    node is not None and node != parent and
                    node.is_indirect_child_of(parent) and
                    node.model == context.application.model and (
                        not self.cb_erase_filter.get_active() or
                        self.erase_filter(node)
                    )
                )
            except Exception:
                raise UserError("An exception occured while evaluating the erase filter expression.")
            if match:
                primitive.Delete(node)

    def tool_draw(self, p1, p2):
        drawing_area = context.application.main.drawing_area
        r1 = drawing_area.screen_to_camera(p1)
        r2 = drawing_area.screen_to_camera(p2)
        context.application.vis_backend.tool("line", r1, r2)

    def tool_special(self, p1, p2):
        pass

    def move_special(self, gl_object1, gl_object2, p1, p2):
        pass

    def click_special(self, gl_object):
        pass
Exemple #30
0
class OptimizeSprings(ImmediateWithMemory):
    description = "Optimize springs"
    menu_info = MenuInfo("default/_Object:tools/_Builder:spring",
                         "_Optimize springs",
                         order=(0, 4, 1, 6, 0, 1))
    authors = [authors.toon_verstraelen]

    parameters_dialog = FieldsDialogSimple(
        "Minimization parameters",
        fields.group.Table(fields=[
            fields.edit.CheckButton(
                label_text="Allow free rotation",
                attribute_name="allow_rotation",
            ),
            fields.faulty.Float(
                label_text="Update interval [s]",
                attribute_name="update_interval",
                low=0.0,
                low_inclusive=True,
            ),
            fields.faulty.Int(label_text="Number of iterations between update",
                              attribute_name="update_steps",
                              minimum=1),
        ]),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
         (gtk.STOCK_OK, gtk.RESPONSE_OK)),
    )

    report_dialog = OptimizationReportDialog()

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        cache = context.application.cache
        for Class in cache.classes:
            if not issubclass(Class, Spring): return False
        if cache.parent is None: return False
        spring_problem = cache.spring_problem
        if spring_problem is None: return False
        if len(spring_problem.frames) == 0: return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.allow_rotation = True
        result.update_interval = 0.4
        result.update_steps = 1
        return result

    def do(self):
        cache = context.application.cache
        parent = cache.parent
        involved_frames = cache.spring_problem.frames
        springs = cache.spring_problem.springs
        max_step = []

        old_transformations = [(frame, frame.transformation)
                               for frame in involved_frames
                               if frame is not None]

        variable_indices = dict((frame, index) for index, frame in enumerate(
            frame for frame in involved_frames if frame is not None))

        cost_function = iterative.expr.Root(1, 10, True)
        for frame in involved_frames:
            if frame is None:
                pass
            elif self.parameters.allow_rotation and isinstance(
                    frame.transformation, Complete):
                variable = iterative.var.Frame(
                    frame.transformation.r,
                    frame.transformation.t,
                )
                cost_function.register_state_variable(variable)
                constraint = iterative.expr.Orthonormality(1e-10)
                constraint.register_input_variable(variable)
                max_step.extend([
                    0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 1.0, 1.0, 1.0
                ])
            elif isinstance(frame.transformation, Translation):
                variable = iterative.var.Translation(
                    frame.transformation.r,
                    frame.transformation.t,
                )
                cost_function.register_state_variable(variable)
                max_step.extend([1.0, 1.0, 1.0])
            else:
                raise UserError(
                    "The involved frames shoud be at least capable of being translated."
                )

        for spring, frames in springs.iteritems():
            spring_term = iterative.expr.Spring(spring.rest_length)
            for target, frame in frames.iteritems():
                if frame is None:
                    spring_term.register_input_variable(
                        iterative.expressions.NoFrame(),
                        target.get_frame_up_to(parent).t)
                else:
                    spring_term.register_input_variable(
                        cost_function.state_variables[variable_indices[frame]],
                        target.get_frame_up_to(frame).t)

        max_step = numpy.array(max_step, float)
        minimize = iterative.alg.DefaultMinimize(
            cost_function,
            max_step,
            max_step * 1e-8,
        )

        result = self.report_dialog.run(
            minimize,
            involved_frames,
            self.parameters.update_interval,
            self.parameters.update_steps,
            len(springs),
        )
        if result != gtk.RESPONSE_OK:
            for frame, transformation in old_transformations:
                frame.transformation = transformation
                frame.invalidate_transformation_list()
            raise CancelException

        for frame, transformation in old_transformations:
            primitive.SetProperty(
                frame,
                "transformation",
                transformation,
                done=True,
            )
Exemple #31
0
class SelectChildrenByExpression(ImmediateWithMemory):
    description = "Select children by expression"
    menu_info = MenuInfo("default/_Select:default", "Children by _expression", order=(0, 3, 0, 4))
    authors = [authors.toon_verstraelen]

    SELECT_PLAIN = 0
    SELECT_RECURSIVE = 1
    SELECT_RECURSIVE_IF_MATCH = 2

    parameters_dialog = FieldsDialogSimple(
        "Select children by expression",
        fields.group.Table(
            fields=[
                fields.edit.ComboBox(
                    choices=[
                        (SELECT_PLAIN, "No"),
                        (SELECT_RECURSIVE, "Yes"),
                        (SELECT_RECURSIVE_IF_MATCH, "Yes if match")
                    ],
                    label_text="Recursive",
                    attribute_name="recursive",
                    show_popup=False
                ),
                fields.faulty.Expression(
                    label_text="Filter expression:",
                    attribute_name="expression",
                    show_popup=True,
                    history_name="filter",
                )
            ],
            label_text="Selection rules"
        ),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK))
    )

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        cache = context.application.cache
        if len(cache.containers_with_children) + len(cache.referents_with_children) == 0: return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.expression = Expression()
        result.recursive = cls.SELECT_PLAIN
        return result

    def do(self):
        cache = context.application.cache
        parents = cache.nodes
        containers = cache.containers_with_children

        main = context.application.main

        def toggle_children(parent):
            for node in parent.children:
                match = self.parameters.expression(node)
                if match:
                    main.toggle_selection(node, on=True)
                if ((self.parameters.recursive == self.SELECT_RECURSIVE_IF_MATCH) and match) or (self.parameters.recursive == self.SELECT_RECURSIVE):
                    if isinstance(node, ParentMixin):
                        toggle_children(node)


        for parent in parents:
            main.toggle_selection(parent, on=False)
        try:
            for container in containers:
                toggle_children(container)
        except Exception:
            main.tree_selection.unselect_all()
            for parent in parents:
                main.toggle_selection(parent, on=True)
            raise UserError("An exception occured while evaluating the filter expression.")
Exemple #32
0
class RotateAboutAxisDialog(ImmediateWithMemory):
    description = "Apply rotation"
    menu_info = MenuInfo("default/_Object:tools/_Transform:dialogs",
                         "Rotate objects about axis",
                         order=(0, 4, 1, 2, 1, 1))
    authors = [authors.toon_verstraelen]

    parameters_dialog = FieldsDialogSimple(
        "Rotation about axis",
        fields.group.Table(
            [
                fields.composed.Translation(
                    label_text="",
                    attribute_name="center",
                    vector_name="c.%s",
                ),
                fields.composed.Rotation(
                    label_text="",
                    attribute_name="rotation",
                )
            ],
            label_text="The rotation axis is defined by center c and axis n."),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
         (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        cache = context.application.cache
        if len(cache.nodes) == 1:
            if not isinstance(cache.last, GLTransformationMixin) or \
               not isinstance(cache.last.transformation, Rotation):
                return False
            if cache.last.get_fixed(): return False
        elif len(cache.nodes) == 2:
            if not ((isinstance(cache.last, GLTransformationMixin)
                     and isinstance(cache.last.transformation, Translation))
                    or isinstance(cache.last, Vector)):
                return False
            if not isinstance(cache.next_to_last, GLTransformationMixin) or \
               not isinstance(cache.next_to_last.transformation, Complete):
                return False
            if cache.last.get_fixed(): return False
        else:
            return False
        if cache.some_nodes_fixed: return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.center = Translation.identity()
        result.rotation = Rotation.identity()
        return result

    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 do(self):
        transformation = self.parameters.center * self.parameters.rotation * self.parameters.center.inv
        for victim in context.application.cache.transformed_nodes:
            primitive.Transform(victim, transformation)
Exemple #33
0
class SketchOptions(GladeWrapper):

    edit_erase_filter = FieldsDialogSimple(
        "Edit the Erase filter",
        fields.faulty.Expression(
            label_text="Erase filter expression",
            attribute_name="erase_filter",
            show_popup=True,
            history_name="filter",
        ),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK))
    )

    def __init__(self):
        GladeWrapper.__init__(self, "plugins/molecular/gui.glade", "wi_sketch", "window")
        self.window.hide()
        self.init_callbacks(self.__class__)
        self.init_proxies([
            "cb_object",
            "cb_vector",
            "cb_erase_filter",
            "bu_edit_erase_filter",
            "la_current",
            "bu_set_atom",
            "cb_bondtype",
            "hbox_atoms",
            "hbox_quickpicks",
            "hbox_fragments",
            "la_fragment",
            "cb_fragment"
        ])

        self.erase_filter = Expression("True")
        #Initialize atom number - this can be changed anytime with the edit_atom_number dialog
        self.atom_number = 6;

        # Initialize the GUI
        #  1) common parts of the comboboxes
        def render_icon(column, cell, model, iter):
            if model.get_value(iter, 0) == "Fragment":
                cell.set_property(
                "pixbuf",
                context.application.plugins.get_node("Atom").icon
                )
            else:
                cell.set_property(
                    "pixbuf",
                    context.application.plugins.get_node(model.get_value(iter, 0)).icon
                )

        #  2) fill the objects combo box
        self.object_store = gtk.ListStore(str)
        self.object_store.append(["Atom"])
        self.object_store.append(["Fragment"])
        self.object_store.append(["Point"])
        self.object_store.append(["Sphere"])
        self.object_store.append(["Box"])
        self.cb_object.set_model(self.object_store)

        renderer_pixbuf = gtk.CellRendererPixbuf()
        self.cb_object.pack_start(renderer_pixbuf, expand=False)
        self.cb_object.set_cell_data_func(renderer_pixbuf, render_icon)
        renderer_text = gtk.CellRendererText()
        self.cb_object.pack_start(renderer_text, expand=True)
        self.cb_object.add_attribute(renderer_text, "text", 0)

        self.cb_object.set_active(0)

        #  3) fill the vector combo box
        self.vector_store = gtk.ListStore(str)
        self.vector_store.append(["Bond"])
        self.vector_store.append(["Arrow"])
        self.vector_store.append(["Spring"])
        self.cb_vector.set_model(self.vector_store)

        renderer_pixbuf = gtk.CellRendererPixbuf()
        self.cb_vector.pack_start(renderer_pixbuf, expand=False)
        self.cb_vector.set_cell_data_func(renderer_pixbuf, render_icon)
        renderer_text = gtk.CellRendererText()
        self.cb_vector.pack_start(renderer_text, expand=True)
        self.cb_vector.add_attribute(renderer_text, "text", 0)

        self.cb_vector.set_active(0)

        # 4) fill the bond type combo box
        self.bondtype_store = gtk.ListStore(str,int)
        self.bondtype_store.append(["Single bond",BOND_SINGLE])
        self.bondtype_store.append(["Double bond",BOND_DOUBLE])
        self.bondtype_store.append(["Triple bond",BOND_TRIPLE])
        self.bondtype_store.append(["Hybrid bond",BOND_HYBRID])
        self.bondtype_store.append(["Hydrogen bond",BOND_HYDROGEN])
        self.cb_bondtype.set_model(self.bondtype_store)

        #no icons like the others, just text here
        renderer_text = gtk.CellRendererText()
        self.cb_bondtype.pack_start(renderer_text, expand=True)
        self.cb_bondtype.add_attribute(renderer_text, "text", 0)

        self.cb_bondtype.set_active(0)

        # register quick pick config setting
        config = context.application.configuration
        config.register_setting(
            "sketch_quickpicks",
            [6,7,8,9,10,11],
            DialogFieldInfo("Sketch tool", (0,2), fields.faulty.IntegerList(
                label_text="Quick pick atoms (applies after restart)",
                attribute_name="sketch_quickpicks",
            )),
        )

        # 5)create the "quick pick" atom buttons
        for index in xrange(len(config.sketch_quickpicks)):
            atomnumber = config.sketch_quickpicks[index]
            bu_element = gtk.Button("")
            bu_element.set_label("%s" % periodic[atomnumber].symbol)
            bu_element.connect("clicked", self.on_bu_element_clicked, index)
            # add to hbox
            self.hbox_quickpicks.pack_start(bu_element)
            bu_element.show()

        # 6)fill the fragment combo box with filenames from share/fragments
        fragment_dir = context.get_share_filename('fragments')
        self.fragment_store = gtk.ListStore(str)
        for filename in sorted(os.listdir(fragment_dir)):
            # Ignore subfolders and files with extension other than cml
            if os.path.isdir (os.path.join (fragment_dir, filename)) or filename[-3:] != 'cml':
                continue
            self.fragment_store.append([filename[:-4]])
        self.cb_fragment.set_model(self.fragment_store)

        renderer_text = gtk.CellRendererText()
        self.cb_fragment.pack_start(renderer_text, expand=True)
        self.cb_fragment.add_attribute(renderer_text, "text", 0)
        self.cb_fragment.set_active(0)

    @property
    def current_object(self):
       return self.object_store.get_value(self.cb_object.get_active_iter(),0)

    @property
    def current_fragment(self):
       return self.fragment_store.get_value(self.cb_fragment.get_active_iter(), 0)

    def on_window_delete_event(self, window, event):
        self.window.hide()
        return True

    def on_bu_edit_erase_filter_clicked(self, button):
        self.edit_erase_filter.run(self)

    def on_bu_set_atom_clicked(self, button):
        self.edit_atom_number = FieldsDialogSimple(
            "Select atom number",
            fields.edit.Element(attribute_name="atom_number"),
            ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK))
        )
        self.edit_atom_number.run(self)
        atom_symbol = periodic[self.atom_number].symbol
        self.la_current.set_label("Current: %s " % str(atom_symbol))

    def on_cb_object_changed(self, combo):
        self.hbox_atoms.hide()
        self.la_current.hide()
        self.hbox_fragments.hide()
        if(self.current_object=="Atom"):
            self.hbox_atoms.show()
            self.la_current.show()
        if(self.current_object=="Fragment"):
            self.cb_fragment.show()
            self.hbox_fragments.show()

    def on_bu_element_clicked(self, widget, index):
        self.atom_number = context.application.configuration.sketch_quickpicks[index]
        atom_symbol = periodic[self.atom_number].symbol
        self.la_current.set_label("Current: %s" % str(atom_symbol))

    def on_cb_vector_changed(self, combo):
        # When the selected object is an atom, show the extra button.
        if (self.vector_store.get_value(self.cb_vector.get_active_iter(),0)=="Bond"):
            self.cb_bondtype.show()
        else:
            self.cb_bondtype.hide()

    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 add_new(self, position, parent):
        new = self.get_new(position)

        if self.current_object == "Fragment":
            result = new.children[1]
            primitive.Add(new, parent)
            UnframeAbsolute = context.application.plugins.get_action("UnframeAbsolute")
            UnframeAbsolute([new])
            #return result
        else:
            primitive.Add(new, parent)
            return new

    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 connect(self, gl_object1, gl_object2):
        try:
            new = context.application.plugins.get_node(
                self.vector_store.get_value(self.cb_vector.get_active_iter(), 0)
            )(targets=[gl_object1, gl_object2])
        except TargetError:
            return

        if(self.vector_store.get_value(self.cb_vector.get_active_iter(), 0)=="Bond"):
            new.set_bond_type(self.bondtype_store.get_value(self.cb_bondtype.get_active_iter(),1))

        primitive.Add(new, common_parent([gl_object1.parent, gl_object2.parent]))

    def erase_at(self, p, parent):
        for node in context.application.main.drawing_area.iter_hits((p[0]-2, p[1]-2, p[0]+2, p[1]+2)):
            try:
                match = (
                    node is not None and node != parent and
                    node.is_indirect_child_of(parent) and
                    node.model == context.application.model and (
                        not self.cb_erase_filter.get_active() or
                        self.erase_filter(node)
                    )
                )
            except Exception:
                raise UserError("An exception occured while evaluating the erase filter expression.")
            if match:
                primitive.Delete(node)

    def tool_draw(self, p1, p2):
        drawing_area = context.application.main.drawing_area
        r1 = drawing_area.screen_to_camera(p1)
        r2 = drawing_area.screen_to_camera(p2)
        context.application.vis_backend.tool("line", r1, r2)

    def tool_special(self, p1, p2):
        pass

    def move_special(self, gl_object1, gl_object2, p1, p2):
        pass

    def click_special(self, gl_object):
        pass
Exemple #34
0
class AutoConnectParameters(AutoConnectMixin, ImmediateWithMemory):
    description = "Add bonds (parameters)"
    menu_info = MenuInfo("default/_Object:tools/_Molecular:add", "_Add bonds (parameters)", order=(0, 4, 1, 5, 1, 1))
    authors = [authors.toon_verstraelen]

    parameters_dialog = FieldsDialogSimple(
        "Bond specification",
        fields.group.Table([
            fields.faulty.Int(
                label_text="Atom number 1",
                attribute_name="number1",
                show_popup=False,
                minimum=1,
                maximum=118
            ),
            fields.faulty.Int(
                label_text="Atom number 2",
                attribute_name="number2",
                show_popup=False,
                minimum=1,
                maximum=118
            ),
            fields.faulty.Length(
                label_text="Maximum bond length",
                attribute_name="distance",
                show_popup=False,
                low=0.0,
                low_inclusive=False
            ),
            fields.edit.ComboBox(
                choices=[
                    (BOND_SINGLE, "Single bond"),
                    (BOND_DOUBLE, "Double bond"),
                    (BOND_TRIPLE, "Triple bond")],
                label_text="Bond type",
                attribute_name="bond_type"
            ),
        ]),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_OK, gtk.RESPONSE_OK))
    )

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        if not AutoConnectMixin.analyze_selection(): return False
        # C) passed all tests:
        return True

    def allow_node(self, node):
        return (
            isinstance(node, context.application.plugins.get_node("Atom")) and
            (
                node.number == self.parameters.number1 or
                node.number == self.parameters.number2
            )
        )

    def get_vector(self, atom1, atom2, distance):
        if (((atom1.number == self.parameters.number1) and
             (atom2.number == self.parameters.number2)) or
            ((atom1.number == self.parameters.number2) and
             (atom2.number == self.parameters.number1))) and \
           atom1 not in atom2.iter_neighbors():
            if self.parameters.distance >= distance:
                return Bond(bond_type=self.parameters.bond_type, targets=[atom1, atom2])
        return None

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        result.number1 = 6
        result.number2 = 6
        result.distance = 0.5
        result.bond_type = BOND_SINGLE
        return result

    def do(self):
        AutoConnectMixin.do(self, max([1, self.parameters.distance]))
Exemple #35
0
class UnitCellToCluster(ImmediateWithMemory):
    description = "Convert the unit cell to a cluster"
    menu_info = MenuInfo("default/_Object:tools/_Unit Cell:default",
                         "_To cluster",
                         order=(0, 4, 1, 4, 0, 0))
    authors = [authors.toon_verstraelen]
    store_last_parameters = False

    parameters_dialog = FieldsDialogSimple(
        "Unit cell to cluster",
        fields.group.Table(
            fields=[
                fields.optional.CheckOptional(
                    fields.composed.ComposedArray(
                        FieldClass=fields.faulty.Float,
                        array_name=(ridge + ".%s"),
                        suffices=["min", "max"],
                        attribute_name="interval_%s" % ridge.lower(),
                        one_row=True,
                        short=False,
                    )) for ridge in ["a", "b", "c"]
            ],
            label_text="The retained region in fractional coordinates:"),
        ((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
         (gtk.STOCK_OK, gtk.RESPONSE_OK)))

    @staticmethod
    def analyze_selection(parameters=None):
        # A) calling ancestor
        if not ImmediateWithMemory.analyze_selection(parameters): return False
        # B) validating
        universe = context.application.model.universe
        if sum(universe.cell.active) == 0: return False
        if hasattr(parameters, "interval_a") and not universe.cell.active[0]:
            return False
        if hasattr(parameters, "interval_b") and not universe.cell.active[1]:
            return False
        if hasattr(parameters, "interval_c") and not universe.cell.active[2]:
            return False
        # C) passed all tests:
        return True

    @classmethod
    def default_parameters(cls):
        result = Parameters()
        universe = context.application.model.universe
        if universe.cell.active[0]:
            result.interval_a = numpy.array([0.0, universe.repetitions[0]],
                                            float)
        if universe.cell.active[1]:
            result.interval_b = numpy.array([0.0, universe.repetitions[1]],
                                            float)
        if universe.cell.active[2]:
            result.interval_c = numpy.array([0.0, universe.repetitions[2]],
                                            float)
        return result

    def do(self):
        universe = context.application.model.universe

        def vector_acceptable(vector, cell_vector):
            return abs(
                numpy.dot(vector, cell_vector) /
                numpy.dot(cell_vector, cell_vector)) < 0.5

        def extend_to_cluster(axis, interval):
            if (interval is None) or isinstance(interval, Undefined): return
            assert universe.cell.active[axis]
            interval.sort()
            index_min = int(numpy.floor(interval[0]))
            index_max = int(numpy.ceil(interval[1]))

            old_points = [
                node for node in universe.children
                if (isinstance(node, GLTransformationMixin)
                    and isinstance(node.transformation, Translation))
            ]
            if len(old_points) == 0: return

            old_connections = [
                node for node in universe.children
                if (isinstance(node, ReferentMixin) and reduce(
                    (lambda x, y: x and y),
                    (isinstance(child, SpatialReference)
                     for child in node.children),
                    True,
                ))
            ]

            # replication of the points
            new_points = {}
            for old_point in old_points:
                # determine the wrapped position
                old_pos = old_point.transformation.t.copy()
                old_frac = universe.cell.to_fractional(old_pos)
                old_index = numpy.floor(old_frac).astype(int)
                old_pos -= universe.cell.to_cartesian(old_index)
                old_frac -= old_index
                del old_index
                # make copies
                for cell_index in xrange(index_min, index_max):
                    position = old_pos + universe.cell.matrix[:,
                                                              axis] * cell_index
                    if (old_frac[axis] + cell_index < interval[0]) or (
                            old_frac[axis] + cell_index > interval[1]):
                        continue
                    state = old_point.__getstate__()
                    state["transformation"] = state[
                        "transformation"].copy_with(t=position)
                    new_point = old_point.__class__(**state)
                    new_points[(old_point, cell_index)] = new_point

            new_connections = []
            # replication of the connections
            for cell_index in xrange(index_min - 1, index_max + 1):
                for connection in old_connections:
                    old_target0 = connection.children[0].target
                    new_target0 = new_points.get((old_target0, cell_index))
                    if new_target0 is None: continue

                    new_targets = [new_target0]

                    for reference in connection.children[1:]:
                        abort = True
                        old_target1 = reference.target
                        for offset in 0, 1, -1:
                            new_target1 = new_points.get(
                                (old_target1, cell_index + offset))
                            if new_target1 is not None:
                                delta = new_target0.transformation.t - new_target1.transformation.t
                                if vector_acceptable(
                                        delta, universe.cell.matrix[:, axis]):
                                    new_targets.append(new_target1)
                                    abort = False
                                    break
                        if abort: break
                    if abort:
                        del new_targets
                        continue

                    state = connection.__getstate__()
                    state["targets"] = new_targets
                    new_connections.append(connection.__class__(**state))

            # remove the existing points and connections

            for node in old_connections:
                primitive.Delete(node)
            del old_connections
            for node in old_points:
                primitive.Delete(node)
            del old_points

            # remove the periodicity

            new_active = universe.cell.active.copy()
            new_active[axis] = False
            new_cell = universe.cell.copy_with(active=new_active)
            primitive.SetProperty(universe, "cell", new_cell)

            # add the new nodes

            for node in new_points.itervalues():
                primitive.Add(node, universe)

            for connection in new_connections:
                primitive.Add(connection, universe)

        if hasattr(self.parameters, "interval_a"):
            extend_to_cluster(0, self.parameters.interval_a)
        if hasattr(self.parameters, "interval_b"):
            extend_to_cluster(1, self.parameters.interval_b)
        if hasattr(self.parameters, "interval_c"):
            extend_to_cluster(2, self.parameters.interval_c)