def _is_there_place( self, atom, x, y): x1, y1 = atom.x, atom.y angle1 = geometry.clockwise_angle_from_east( x-x1, y-y1) for n in atom.neighbors: angle = geometry.clockwise_angle_from_east( n.x-x1, n.y-y1) if abs( angle - angle1) < 0.3: return False return True
def _is_there_place(self, atom, x, y): x1, y1 = atom.x, atom.y angle1 = geometry.clockwise_angle_from_east(x - x1, y - y1) for n in atom.neighbors: angle = geometry.clockwise_angle_from_east(n.x - x1, n.y - y1) if abs(angle - angle1) < 0.3: return False return True
def _process_simply_anelated_ring( self, ring, base): out = [] inter = [v for v in ring if v.x != None and v.y != None] if len( inter) == 1: # rings are connected via one atom v = inter.pop() # the atom of concatenation ring = self.mol.sort_vertices_in_path( ring, start_from=v) base_neighs = [a for a in v.get_neighbors() if a in base] if len( base_neighs) < 2: raise "this should not happen" d1 = base_neighs[0] d2 = base_neighs[1] ca1 = geometry.clockwise_angle_from_east( v.x-d1.x, v.y-d1.y) ca2 = geometry.clockwise_angle_from_east( v.x-d2.x, v.y-d2.y) ca = (ca1+ca2)/2 if abs( ca1-ca2) < pi: ca += -pi/2 else: ca += pi/2 size = len( ring) da = deg_to_rad(180 -180.0*(size-2)/size) gcoords = gen_angle_stream( da, start_from=ca + da/2) ring.remove( v) # here we generate the coords self.apply_gen_to_atoms( gcoords, ring, v) ring.append( v) out += ring elif len( inter) == 2: # there are two atoms common to the rings v1, v2 = inter # the atoms of concatenation ring = self.mol.sort_vertices_in_path( ring, start_from=v1) ring.remove( v1) ring.remove( v2) if not v1 in ring[0].get_neighbors(): v1, v2 = v2, v1 side = sum( [geometry.on_which_side_is_point((v1.x,v1.y,v2.x,v2.y),(v.x,v.y)) for v in base]) if not side: warnings.warn( "this should not happen") ca = geometry.clockwise_angle_from_east( v1.x-v2.x, v1.y-v2.y) size = len( ring)+2 da = deg_to_rad(180 -180.0*(size-2)/size) if side > 0: da = -da gcoords = gen_angle_stream( da, start_from=ca+da) self.apply_gen_to_atoms( gcoords, ring, v1) ring.append( v1) ring.append( v2) out += ring else: # there are more than 2 atoms common if len( ring) == len( base): out += self._process_multi_anelated_ring( ring, angle_shift=15) #raise( "i don't how to handle this yet") else: out += self._process_multi_anelated_ring( ring) return out
def get_angle_gradient2( self, opt_angle, refv, v1, v2): ang1 = geometry.clockwise_angle_from_east( v1.x-refv.x, v1.y-refv.y) ang2 = geometry.clockwise_angle_from_east( v2.x-refv.x, v2.y-refv.y) ang = ang1 - ang2 sign = -geometry.on_which_side_is_point( (refv.x, refv.y, v1.x, v1.y), (v2.x, v2.y)) while ang < 0: ang += 2*pi if ang > pi: ang = 2*pi - ang sign *= -1 dang = (ang - opt_angle) / 2 gx1 = (cos( ang1 - sign*dang) - cos( ang1)) * sqrt( (refv.x-v1.x)**2 + (refv.y-v1.y)**2) #self.bond_length #(v1.x-refv.x) gy1 = (sin( ang1 - sign*dang) - sin( ang1)) * sqrt( (refv.x-v1.x)**2 + (refv.y-v1.y)**2) #self.bond_length #(v1.y-refv.y) gx2 = (cos( ang2 + sign*dang) - cos( ang2)) * sqrt( (refv.x-v2.x)**2 + (refv.y-v2.y)**2) #self.bond_length #(v2.x-refv.x) gy2 = (sin( ang2 + sign*dang) - sin( ang2)) * sqrt( (refv.x-v2.x)**2 + (refv.y-v2.y)**2) #self.bond_length #(v2.y-refv.y) # control ang1 = geometry.clockwise_angle_from_east( v1.x-refv.x+gx1, v1.y-refv.y+gy1) ang2 = geometry.clockwise_angle_from_east( v2.x-refv.x+gx2, v2.y-refv.y+gy2) ang = ang1 - ang2 sign = geometry.on_which_side_is_point( (refv.x, refv.y, v1.x, v1.y), (v2.x, v2.y)) while ang < 0: ang += 2*pi #sign *= -1 if ang > pi: ang = 2*pi - ang #sign *= -1 dang2 = (ang - opt_angle) / 2 if abs( dang2) > abs( dang): print "f**k", rad_to_deg( ang1), rad_to_deg( ang2), rad_to_deg( dang) else: #rint "good", rad_to_deg( ang1), rad_to_deg( ang2), rad_to_deg( dang) pass return gx1, gy1, gx2, gy2
def _find_place_around_atom( self, atom): x, y = atom.x, atom.y coords = [(a.x,a.y) for a in atom.neighbors] # now we can compare the angles angles = [geometry.clockwise_angle_from_east( x1-x, y1-y) for x1,y1 in coords] angles.append( 2*math.pi + min( angles)) angles.sort() angles.reverse() diffs = misc.list_difference( angles) i = diffs.index( max( diffs)) angle = (angles[i] +angles[i+1]) / 2 return angle
def _process_multi_anelated_ring( self, ring, angle_shift=0): out = [] to_go = [v for v in ring if v.x == None or v.y == None] if not to_go: # it was all already done return [] back = [v for v in ring if v.x != None and v.y != None] sorted_back = self.mol.sort_vertices_in_path( back) if not sorted_back: # the already set atoms are not in one path - we have to process it "per partes" # it should not happen with the construction method we use raise( "i am not able to handle this, it should normaly not happen. please send me the input.") else: v1 = sorted_back[0] v2 = sorted_back[-1] v3 = sorted_back[1] to_go = self.mol.sort_vertices_in_path( to_go) if v1 not in to_go[0].get_neighbors(): v1, v2 = v2, v1 blocked_angle = sum_of_ring_internal_angles( len( back)) overall_angle = sum_of_ring_internal_angles( len( ring)) da = optimal_ring_iternal_angle( len( ring)) # internal angle # if there are 2 rings of same size inside each other, we need to use the angle_shift if angle_shift: da += 2*angle_shift/(len( to_go)) ca = deg_to_rad( 180-(overall_angle - blocked_angle - len( to_go) * da + angle_shift)/2) # connection angle side = sum( [geometry.on_which_side_is_point( (v1.x,v1.y,v2.x,v2.y),(v.x,v.y)) for v in back if v != v1 and v != v2]) # we need to make sure that the ring is drawn on the right side if side > 0: ca = -ca ca += geometry.clockwise_angle_from_east( v1.x-v2.x, v1.y-v2.y) da = 180-da # for drawing we use external angle # we must ensure that the ring will progress towards the second end if geometry.on_which_side_is_point( (v1.x,v1.y,v3.x,v3.y),(v2.x,v2.y)) < 0: da = -da # dry run to see where we get gcoords = gen_angle_stream( deg_to_rad( da), start_from= ca) x, y = v1.x, v1.y for i in range( len( to_go) +1): a = gcoords.next() x += self.bond_length*cos( a) y += self.bond_length*sin( a) # end of dry run, we can scale the bond_length now length = geometry.line_length( (v1.x,v1.y,v2.x,v2.y)) real_length = geometry.line_length( (v1.x,v1.y,x,y)) bl = self.bond_length * length / real_length gcoords = gen_angle_stream( deg_to_rad( da), start_from= ca) # and here we go self.apply_gen_to_atoms( gcoords, to_go, v1, bond_length=bl) out += to_go return out
def _find_place_around_atom(self, atom): x, y = atom.x, atom.y coords = [(a.x, a.y) for a in atom.neighbors] # now we can compare the angles angles = [ geometry.clockwise_angle_from_east(x1 - x, y1 - y) for x1, y1 in coords ] angles.append(2 * math.pi + min(angles)) angles.sort() angles.reverse() diffs = misc.list_difference(angles) i = diffs.index(max(diffs)) angle = (angles[i] + angles[i + 1]) / 2 return angle
def _continue_with_the_coords( self, mol, processed=[]): """processes the atoms in circles around the backbone (processed) until all is done""" while processed: new_processed = [] for v in processed: if len( [o for o in self.mol.vertices if o.x == None]) == 0: # its all done return # look if v is part of a ring ring = None for r in self.rings: if v in r: ring = r break if not ring: # v is not in a ring - we can continue new_processed += self.process_atom_neigbors( v) else: # v is in ring so we process the ring if len( processed) > 1 and mol.defines_connected_subgraph_v( processed) and set( processed) <= ring: new_processed += self.process_all_anelated_rings( processed) else: self.rings.remove( ring) ring = mol.sort_vertices_in_path( ring, start_from=v) ring.remove( v) d = [a for a in v.get_neighbors() if a.x != None and a.y != None][0] # should always work ca = geometry.clockwise_angle_from_east( v.x-d.x, v.y-d.y) size = len( ring)+1 da = deg_to_rad( 180 -180*(size-2)/size) gcoords = gen_angle_stream( da, start_from=ca-pi/2+da/2) # here we generate the coords self.apply_gen_to_atoms( gcoords, ring, v) ring.append( v) new_processed += ring new_processed += self.process_all_anelated_rings( ring) processed = new_processed
def process_atom_neigbors( self, v): def get_angle_at_side( v, d, d2, relation, attach_angle): if attach_angle == 180: # shortcut return attach_angle side = geometry.on_which_side_is_point( (d.x,d.y,v.x,v.y), (d2.x,d2.y)) an = angle + deg_to_rad( attach_angle) x = v.x + self.bond_length*cos( an) y = v.y + self.bond_length*sin( an) if relation*side == geometry.on_which_side_is_point( (d.x,d.y,v.x,v.y), (x,y)): return attach_angle else: return -attach_angle to_go = [a for a in v.get_neighbors() if a.x == None or a.y == None] done = [a for a in v.get_neighbors() if a not in to_go] if len( done) == 1 and (len( to_go) == 1 or len( to_go) == 2 and [1 for _t in to_go if _t in self.stereo]): # only simple non-branched chain or branched with stereo d = done[0] if len( to_go) == 1: t = to_go[0] else: t = [_t for _t in to_go if _t in self.stereo][0] # decide angle angle_to_add = 120 bond = v.get_edge_leading_to( t) # triple bonds if 3 in [_e.order for _e in v.get_neighbor_edges()]: angle_to_add = 180 # cumulated double bonds if bond.order == 2: _b = v.get_edge_leading_to( d) if _b.order == 2: angle_to_add = 180 angle = geometry.clockwise_angle_from_east( d.x-v.x, d.y-v.y) dns = d.get_neighbors() placed = False # stereochemistry (E/Z) if t in self.stereo: ss = [st for st in self.stereo[t] if not None in st.get_other_end( t).coords[:2]] if ss: st = ss[0] # we choose the first one if more are present d2 = st.get_other_end( t) # other is processed, we need to adapt relation = st.value == st.OPPOSITE_SIDE and -1 or 1 angle_to_add = get_angle_at_side( v, d, d2, relation, angle_to_add) placed = True if not placed and len( dns) == 2: # to support the all trans of simple chains without stereochemistry d2 = (dns[0] == v) and dns[1] or dns[0] if d2.x != None and d2.y != None: angle_to_add = get_angle_at_side( v, d, d2, -1, angle_to_add) an = angle + deg_to_rad( angle_to_add) t.x = v.x + self.bond_length*cos( an) t.y = v.y + self.bond_length*sin( an) if len( to_go) > 1: self.process_atom_neigbors( v) else: # branched chain angles = [geometry.clockwise_angle_from_east( at.x-v.x, at.y-v.y) for at in done] angles.append( 2*pi + min( angles)) angles.sort() angles.reverse() diffs = misc.list_difference( angles) i = diffs.index( max( diffs)) angle = (angles[i] -angles[i+1]) / (len( to_go)+1) gcoords = gen_coords_from_stream( gen_angle_stream( angle, start_from=angles[i+1]+angle), length = self.bond_length) for a in to_go: dx, dy = gcoords.next() a.x = v.x + dx a.y = v.y + dy return to_go