def on_begin( self, scaling=None): self.paper.unselect_all() if self.paper.get_paper_property( 'crop_svg'): if len( self.paper.find_all()) <= 1: # background only Store.log( _('There is nothing to export. If you want to export an empty paper disable cropping of the drawing in the File/Properties menu.'), message_type="error") return 0 x1, y1, x2, y2 = self.paper.get_cropping_bbox() dx = x2-x1 dy = y2-y1 scalex, scaley = scaling or self.get_scaling( dx, dy) if not scalex: # the setting of scaling was canceled return 0 self.transformer = transform.transform() self.transformer.set_move( -x1, -y1) self.transformer.set_scaling_xy( scalex, scaley) else: dx = Screen.mm_to_px( self.paper._paper_properties['size_x']) dy = Screen.mm_to_px( self.paper._paper_properties['size_y']) scalex, scaley = scaling or self.get_scaling( dx, dy) if not scalex: # the setting of scaling was canceled return 0 self.transformer = transform.transform() self.transformer.set_scaling_xy( scalex, scaley) x1, y1, x2, y2 = self.transformer.transform_4( (0, 0, dx, dy)) self.pagesize = tuple( map( round, (x2-x1, y2-y1))) self.attrs['text_to_curves'] = False self.converter = self.converter_class( **self.attrs) return 1
def convert_selected_to_linear_fragment(paper): # check the selection bond_length = 10 changes = False mols = [ m for m in paper.selected_to_unique_top_levels()[0] if m.object_type == "molecule" ] for mol in mols: vs = [v for v in mol.vertices if v in paper.selected] try: change = atoms_to_linear_fragment(mol, vs, bond_length=bond_length) except ValueError: Store.log(_("The selection does not define connected subgraph"), message_type="error") return except excs.bkchem_graph_error, e: if e.id == "circular_selection": Store.log(e.value, message_type="error") else: raise else: changes = changes or change if changes: f = mol.create_fragment( "linear_form", mol.vertex_subgraph_to_edge_subgraph(vs), vs, type="linear_form") f.properties['bond_length'] = bond_length
def on_begin( self): self.paper.unselect_all() scale = 720.0/self.paper.winfo_fpixels( '254m') if self.paper.get_paper_property( 'crop_svg'): margin = self.paper.get_paper_property('crop_margin') items = list( self.paper.find_all()) items.remove( self.paper.background) if not items: Store.log( _('There is nothing to export. If you want to export an empty paper disable cropping of the drawing in the File/Properties menu.'), message_type="error") return 0 x1, y1, x2, y2 = self.paper.list_bbox( items) self.transformer = transform.transform() self.transformer.set_move( -x1+margin, -y1+margin) self.transformer.set_scaling( scale) dx = x2-x1 +2*margin dy = y2-y1 +2*margin else: self.transformer = transform.transform() self.transformer.set_scaling( scale) dx = Screen.mm_to_px( self.paper._paper_properties['size_x']) dy = Screen.mm_to_px( self.paper._paper_properties['size_y']) self.canvas = self.init_canvas( pagesize=(scale*dx, scale*dy)) self.converter = self.converter_class() return 1
def ask_name_for_selected(paper): """opens dialog for input of molecule name and sets it""" top_levels, unique = paper.selected_to_unique_top_levels() ms = [o for o in top_levels if isinstance(o, molecule)] if not ms: tkMessageBox.showerror( _("No molecule selected."), _("At least one molecule must be selected. Please select it.")) return dial = Pmw.PromptDialog(paper, title=_('Name'), label_text=_('Name:'), entryfield_labelpos='n', buttons=(_('OK'), _('Cancel'))) # if only one mol is selected use it as default if len(ms) == 1 and ms[0].name: dial.insertentry(0, ms[0].name) res = dial.activate() if res == _('OK'): name = dial.get() else: return for m in ms: m.name = name Store.log(_('Name %s was set to molecule(s)') % name) paper.start_new_undo_record()
def ask_name_for_selected( paper): """opens dialog for input of molecule name and sets it""" top_levels, unique = paper.selected_to_unique_top_levels() ms = [o for o in top_levels if isinstance( o, molecule)] if not ms: tkMessageBox.showerror( _("No molecule selected."), _("At least one molecule must be selected. Please select it.")) return dial = Pmw.PromptDialog( paper, title=_('Name'), label_text=_('Name:'), entryfield_labelpos = 'n', buttons=(_('OK'),_('Cancel'))) # if only one mol is selected use it as default if len( ms) == 1 and ms[0].name: dial.insertentry( 0, ms[0].name) res = dial.activate() if res == _('OK'): name = dial.get() else: return for m in ms: m.name = name Store.log( _('Name %s was set to molecule(s)') % name) paper.start_new_undo_record()
def on_begin(self): self.paper.unselect_all() scale = 720.0 / self.paper.winfo_fpixels('254m') if self.paper.get_paper_property('crop_svg'): margin = self.paper.get_paper_property('crop_margin') items = list(self.paper.find_all()) items.remove(self.paper.background) if not items: Store.log(_( 'There is nothing to export. If you want to export an empty paper disable cropping of the drawing in the File/Properties menu.' ), message_type="error") return 0 x1, y1, x2, y2 = self.paper.list_bbox(items) self.transformer = transform.transform() self.transformer.set_move(-x1 + margin, -y1 + margin) self.transformer.set_scaling(scale) dx = x2 - x1 + 2 * margin dy = y2 - y1 + 2 * margin else: self.transformer = transform.transform() self.transformer.set_scaling(scale) dx = Screen.mm_to_px(self.paper._paper_properties['size_x']) dy = Screen.mm_to_px(self.paper._paper_properties['size_y']) self.canvas = self.init_canvas(pagesize=(scale * dx, scale * dy)) self.converter = self.converter_class() return 1
def convert_selected_to_linear_fragment( paper): # check the selection bond_length = 10 changes = False mols = [m for m in paper.selected_to_unique_top_levels()[0] if m.object_type == "molecule"] for mol in mols: vs = [v for v in mol.vertices if v in paper.selected] try: change = atoms_to_linear_fragment( mol, vs, bond_length=bond_length) except ValueError: Store.log( _("The selection does not define connected subgraph"), message_type="error") return except excs.bkchem_graph_error as e: if e.id == "circular_selection": Store.log( e.value, message_type="error") else: raise else: changes = changes or change if changes: f = mol.create_fragment( "linear_form", mol.vertex_subgraph_to_edge_subgraph( vs), vs, type="linear_form") f.properties['bond_length'] = bond_length if changes: paper.start_new_undo_record()
def atoms_to_linear_fragment( mol, vs, bond_length=10): changes = False if vs and mol.defines_connected_subgraph_v( vs): # the selection is connected for v in vs: if len( [n for n in v.neighbors if n in vs]) > 2: Store.log( _("The selection is not linear - there are some splittings."), message_type="error") return # ok, we are clear # here comes the code to do the work # we start from the end atom that is more on the left side changes = True ends = [v for v in vs if len( [n for n in v.neighbors if n in vs]) == 1] if not ends and len( vs) != 1: # whole ring is selected, how could this be possibly linearized? raise excs.bkchem_graph_error( "circular_selection", _("The selected part of a molecule is a whole ring, there is no way to linearize it")) if len( vs) == 1: start = list(vs)[0] end = start else: start = ends[0].x > ends[1].x and ends[1] or ends[0] end = start == ends[0] and ends[1] or ends[0] current = start x = current.x y = current.y processed = set() current_e = None while 1: processed.add( current) current.show_hydrogens = True current.redraw() if current != start: dx = x - current.bbox()[0] + bond_length dy = start.y - current.y # move all neighbors that are not selected with their fragments ps = mol.get_pieces_after_edge_removal( current_e) if len( ps) == 2: p = current in ps[0] and ps[0] or ps[1] for a in p: a.move( dx, dy) else: # we are in a ring - move only current current.move( dx, dy) x = current.bbox()[2] if current != end: new = [n for n in current.neighbors if n in vs and n not in processed][0] current_e = new.get_edge_leading_to( current) current = new else: break mol.redraw() return changes else: raise ValueError, "the vertices do not define connected subgraph"
def set_atom_number( atoms): dial = Pmw.PromptDialog( Store.app, title=_('Atom number'), label_text=_('Enter atom number:'), entryfield_labelpos = 'w', buttons=(_('OK'),_('Cancel'))) res = dial.activate() if res == _('OK'): for a in atoms: a.number = dial.get() Store.log( _("Number %s was set to atom(s).") % dial.get(), message_type="info")
def set_atom_number(atoms): dial = Pmw.PromptDialog(Store.app, title=_('Atom number'), label_text=_('Enter atom number:'), entryfield_labelpos='w', buttons=(_('OK'), _('Cancel'))) res = dial.activate() if res == _('OK'): for a in atoms: a.number = dial.get() Store.log(_("Number %s was set to atom(s).") % dial.get(), message_type="info")
def ask_id_for_selected(paper): """opens dialog for input of molecule ID and sets it""" top_levels, unique = paper.selected_to_unique_top_levels() ms = [o for o in top_levels if isinstance(o, molecule)] if not ms: tkMessageBox.showerror( _("No molecule selected."), _("At least one molecule must be selected. Please select it.")) return if len(ms) > 1: tkMessageBox.showerror( _("Only one molecule should be selected."), _("ID must be unique value, therefore it is obviously possible to set it to one molecule only. Please select only one molecule" )) return m = ms[0] while 1: dial = Pmw.PromptDialog(paper, title=_('Id'), label_text=_('Id:'), entryfield_labelpos='n', buttons=(_('OK'), _('Cancel'))) # put the recent value if m.id: dial.insertentry(0, m.id) res = dial.activate() if res == _('OK'): id = dial.get() else: return collision = 0 for mol in paper.molecules: if mol != m and mol.id == id: tkMessageBox.showerror( _("ID collision"), _("This ID is already used, use a different one")) collision = 1 break if not collision: break m.id = id Store.log(_('ID %s was set to molecule') % id) paper.start_new_undo_record()
def check_linear_fragments( paper): """checks the state of linear fragments present on the paper and resets their appearance""" #mols = paper.um.get_changed_molecules() last_record = paper.um.get_last_record() for mol in paper.molecules: to_del = set() fs = [f for f in mol.fragments if f.type == "linear_form"] if fs and (last_record == None or last_record.object_changed( mol)): for f in fs: if mol.check_linear_form_fragment( f) == False: to_del.add( f) for f in to_del: Store.log( _('The linear form was no longer consistent - it has been removed')) mol.delete_fragment( f)
def ask_display_form_for_selected(paper): top_levels, unique = paper.selected_to_unique_top_levels() ms = [o for o in top_levels if isinstance(o, molecule)] if not ms: tkMessageBox.showerror( _("No molecule selected."), _("At least one molecule must be selected. Please select it.")) return dial = Pmw.Dialog( paper, title=_('Display Form'), #defaultbutton = _('OK'), buttons=(_('OK'), _('Cancel'))) input = widgets.HTMLLikeInput(dial.interior()) input.pack() input.editPool.focus_set() # if only one mol is selected use it as default if len(ms) == 1 and ms[0].display_form: input.text = ms[0].display_form res = dial.activate() if res == _('OK'): df = input.editPool.get() df = unicode(df).encode('utf-8') ## catch not well-formed text try: xml.sax.parseString("<a>%s</a>" % df, xml.sax.ContentHandler()) except xml.sax.SAXParseException: df = xml.sax.saxutils.escape(df) # the second round of try: except: should catch problems not # related to XML wellfomedness but rather to encoding try: xml.sax.parseString("<a>%s</a>" % df, xml.sax.ContentHandler()) except xml.sax.SAXParseException: tkMessageBox.showerror( _("Parse Error"), _("Unable to parse the text-\nprobably problem with input encoding!" )) Store.app.paper.bell() return else: return for m in ms: m.display_form = df Store.log(_('Display form %s was set to molecule(s)') % df) paper.start_new_undo_record()
def check_linear_fragments(paper): """checks the state of linear fragments present on the paper and resets their appearance""" #mols = paper.um.get_changed_molecules() last_record = paper.um.get_last_record() for mol in paper.molecules: to_del = set() fs = [f for f in mol.fragments if f.type == "linear_form"] if fs and (last_record == None or last_record.object_changed(mol)): for f in fs: if mol.check_linear_form_fragment(f) == False: to_del.add(f) for f in to_del: Store.log( _('The linear form was no longer consistent - it has been removed' )) mol.delete_fragment(f)
def ask_id_for_selected( paper): """opens dialog for input of molecule ID and sets it""" top_levels, unique = paper.selected_to_unique_top_levels() ms = [o for o in top_levels if isinstance( o, molecule)] if not ms: tkMessageBox.showerror( _("No molecule selected."), _("At least one molecule must be selected. Please select it.")) return if len( ms) > 1: tkMessageBox.showerror( _("Only one molecule should be selected."), _("ID must be unique value, therefore it is obviously possible to set it to one molecule only. Please select only one molecule")) return m = ms[0] while 1: dial = Pmw.PromptDialog( paper, title=_('Id'), label_text=_('Id:'), entryfield_labelpos = 'n', buttons=(_('OK'),_('Cancel'))) # put the recent value if m.id: dial.insertentry( 0, m.id) res = dial.activate() if res == _('OK'): id = dial.get() else: return collision = 0 for mol in paper.molecules: if mol != m and mol.id == id: tkMessageBox.showerror( _("ID collision"), _("This ID is already used, use a different one")) collision = 1 break if not collision: break m.id = id Store.log( _('ID %s was set to molecule') % id) paper.start_new_undo_record()
def ask_display_form_for_selected( paper): top_levels, unique = paper.selected_to_unique_top_levels() ms = [o for o in top_levels if isinstance( o, molecule)] if not ms: tkMessageBox.showerror( _("No molecule selected."), _("At least one molecule must be selected. Please select it.")) return dial = Pmw.Dialog( paper, title=_('Display Form'), #defaultbutton = _('OK'), buttons=(_('OK'),_('Cancel'))) input = widgets.HTMLLikeInput( dial.interior()) input.pack() input.editPool.focus_set() # if only one mol is selected use it as default if len( ms) == 1 and ms[0].display_form: input.text = ms[0].display_form res = dial.activate() if res == _('OK'): df = input.editPool.get() df = unicode( df).encode( 'utf-8') ## catch not well-formed text try: xml.sax.parseString( "<a>%s</a>" % df, xml.sax.ContentHandler()) except xml.sax.SAXParseException: df = xml.sax.saxutils.escape( df) # the second round of try: except: should catch problems not # related to XML wellfomedness but rather to encoding try: xml.sax.parseString( "<a>%s</a>" % df, xml.sax.ContentHandler()) except xml.sax.SAXParseException: tkMessageBox.showerror( _("Parse Error"), _("Unable to parse the text-\nprobably problem with input encoding!")) Store.app.paper.bell() return else: return for m in ms: m.display_form = df Store.log( _('Display form %s was set to molecule(s)') % df) paper.start_new_undo_record()
def compute_oxidation_number( paper): v = validator.validator() v.validate( paper.selected_atoms) logged = False if v.report.group_atoms: Store.log( _("Groups must be expanded to compute oxidation number for them."), message_type="hint") logged = True # we have to check if the neighbors of the atoms we are processing are not groups or so... ns = list( reduce( operator.or_, map(set, [a.neighbors for a in paper.selected_atoms]))) v.validate( ns) if v.report.group_atoms or v.report.text_atoms: Store.log( _("Unexpanded groups or text-only atoms may cause incorrect computation of oxidation number."), message_type="warning") logged = True for a in paper.selected_atoms: if isinstance( a, atom): oxes = a.get_marks_by_type( "oxidation_number") if not oxes: a.set_mark( "oxidation_number", draw=a.drawn) elif a.drawn: oxes[0].redraw() paper.start_new_undo_record() if not logged: Store.log( _("You can move and delete the created oxidation numbers in the mark mode"), message_type="hint")
def create_fragment_from_selected(paper): top_levels, unique = paper.selected_to_unique_top_levels() if len(top_levels) != 1: Store.log( _("The selected items must be part of exactly one molecule."), message_type="error") return mol = top_levels[0] es = [e for e in paper.selected if e in mol.edges] vs = [v for v in paper.selected if v in mol.vertices] # ask for name dial = Pmw.PromptDialog(paper, title=_('Fragment name'), label_text=_('Enter fragment name:'), entryfield_labelpos='w', buttons=(_('OK'), _('Cancel')), defaultbutton=_('OK')) res = dial.activate() if res == _('OK'): if mol.create_fragment(dial.get(), es, vs): Store.log(_( "The bonds and atoms were used for creation of a new molecular fragment." ), message_type="info") else: Store.log(_( "The bonds and atoms could not have been used for creation of a new molecular fragment, they are probably not defining a connected subgraph of the molecular graph." ), message_type="warning")
def compute_oxidation_number(paper): v = validator.validator() v.validate(paper.selected_atoms) logged = False if v.report.group_atoms: Store.log( _("Groups must be expanded to compute oxidation number for them."), message_type="hint") logged = True # we have to check if the neighbors of the atoms we are processing are not groups or so... ns = list( reduce(operator.or_, map(set, [a.neighbors for a in paper.selected_atoms]))) v.validate(ns) if v.report.group_atoms or v.report.text_atoms: Store.log(_( "Unexpanded groups or text-only atoms may cause incorrect computation of oxidation number." ), message_type="warning") logged = True for a in paper.selected_atoms: if isinstance(a, atom): oxes = a.get_marks_by_type("oxidation_number") if not oxes: a.set_mark("oxidation_number", draw=a.drawn) elif a.drawn: oxes[0].redraw() paper.start_new_undo_record() if not logged: Store.log(_( "You can move and delete the created oxidation numbers in the mark mode" ), message_type="hint")
def log_atom_type( vtype): """according to vtype tells the user how an atom text was interpreted""" if vtype == "atom": Store.log( _("BKChem interpreted the entered text as an atom")) elif vtype == "group": Store.log( _("BKChem thinks it can interpret the entered text as a group, try to expand it to find out how it was interpreted.")) elif vtype == "textatom": Store.log( _("BKChem could not interpret the entered text as anything with chemical meaning"))
def log_atom_type(vtype): """according to vtype tells the user how an atom text was interpreted""" if vtype == "atom": Store.log(_("BKChem interpreted the entered text as an atom")) elif vtype == "group": Store.log( _("BKChem thinks it can interpret the entered text as a group, try to expand it to find out how it was interpreted." )) elif vtype == "textatom": Store.log( _("BKChem could not interpret the entered text as anything with chemical meaning" ))
def create_fragment_from_selected( paper): top_levels, unique = paper.selected_to_unique_top_levels() if len( top_levels) != 1: Store.log( _("The selected items must be part of exactly one molecule."), message_type="error") return mol = top_levels[0] es = [e for e in paper.selected if e in mol.edges] vs = [v for v in paper.selected if v in mol.vertices] # ask for name dial = Pmw.PromptDialog( paper, title=_('Fragment name'), label_text=_('Enter fragment name:'), entryfield_labelpos = 'w', buttons=(_('OK'),_('Cancel')), defaultbutton=_('OK')) res = dial.activate() if res == _('OK'): if mol.create_fragment( dial.get(), es, vs): Store.log( _("The bonds and atoms were used for creation of a new molecular fragment."), message_type="info") else: Store.log( _("The bonds and atoms could not have been used for creation of a new molecular fragment, they are probably not defining a connected subgraph of the molecular graph."), message_type="warning")
def atoms_to_linear_fragment(mol, vs, bond_length=10): changes = False if vs and mol.defines_connected_subgraph_v(vs): # the selection is connected for v in vs: if len([n for n in v.neighbors if n in vs]) > 2: Store.log(_( "The selection is not linear - there are some splittings." ), message_type="error") return # ok, we are clear # here comes the code to do the work # we start from the end atom that is more on the left side changes = True ends = [v for v in vs if len([n for n in v.neighbors if n in vs]) == 1] if not ends and len(vs) != 1: # whole ring is selected, how could this be possibly linearized? raise excs.bkchem_graph_error( "circular_selection", _("The selected part of a molecule is a whole ring, there is no way to linearize it" )) if len(vs) == 1: start = list(vs)[0] end = start else: start = ends[0].x > ends[1].x and ends[1] or ends[0] end = start == ends[0] and ends[1] or ends[0] current = start x = current.x y = current.y processed = set() current_e = None while 1: processed.add(current) current.show_hydrogens = True current.redraw() if current != start: dx = x - current.bbox()[0] + bond_length dy = start.y - current.y # move all neighbors that are not selected with their fragments ps = mol.get_pieces_after_edge_removal(current_e) if len(ps) == 2: p = current in ps[0] and ps[0] or ps[1] for a in p: a.move(dx, dy) else: # we are in a ring - move only current current.move(dx, dy) x = current.bbox()[2] if current != end: new = [ n for n in current.neighbors if n in vs and n not in processed ][0] current_e = new.get_edge_leading_to(current) current = new else: break mol.redraw() return changes else: raise ValueError, "the vertices do not define connected subgraph"
from __future__ import print_function import math import operator from singleton_store import Store bs = [b for b in App.paper.selected if b.object_type == "bond"] if not len(bs) == 2: Store.log(_("You have to have 2 bonds selected"), message_type="hint") else: b1, b2 = bs center = set(b1.vertices) & set(b2.vertices) if center: a11 = center.pop() a12 = b1.atom1 == a11 and b1.atom2 or b1.atom1 a22 = b2.atom1 == a11 and b2.atom2 or b2.atom1 v1 = (a12.x - a11.x, a12.y - a11.y, a12.z - a11.z) v2 = (a22.x - a11.x, a22.y - a11.y, a22.z - a11.z) print(v1, v2) else: v1 = (b1.atom1.x - b1.atom2.x, b1.atom1.y - b1.atom2.y, b1.atom1.z - b1.atom2.z) v2 = (b2.atom1.x - b2.atom2.x, b2.atom1.y - b2.atom2.y, b2.atom1.z - b2.atom2.z) dot = sum(map(operator.mul, v1, v2)) dv1 = math.sqrt(sum(x**2 for x in v1)) dv2 = math.sqrt(sum(x**2 for x in v2)) cos_a = dot / dv1 / dv2