Beispiel #1
0
 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
Beispiel #2
0
 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
Beispiel #3
0
 def find_least_crowded_place_around_atom( self, a, range=10):
   atms = a.neighbors
   x, y = a.get_xy()
   if not atms:
     # single atom molecule
     if a.show_hydrogens and a.pos == "center-first":
       return x -range, y
     else:
       return x +range, y
   angles = [geometry.clockwise_angle_from_east( at.x-a.x, at.y-a.y) for at in atms]
   angles.append( 2*pi + min( angles))
   angles = sorted(angles, reverse=True)
   diffs = misc.list_difference( angles)
   i = diffs.index( max( diffs))
   angle = (angles[i] +angles[i+1]) / 2
   return x +range*cos( angle), y +range*sin( angle)
Beispiel #4
0
 def find_least_crowded_place_around_atom(self, a, range=10):
     atms = a.neighbors
     x, y = a.get_xy()
     if not atms:
         # single atom molecule
         if a.show_hydrogens and a.pos == "center-first":
             return x - range, y
         else:
             return x + range, y
     angles = [
         geometry.clockwise_angle_from_east(at.x - a.x, at.y - a.y)
         for at in atms
     ]
     angles.append(2 * pi + min(angles))
     angles = sorted(angles, reverse=True)
     diffs = misc.list_difference(angles)
     i = diffs.index(max(diffs))
     angle = (angles[i] + angles[i + 1]) / 2
     return x + range * cos(angle), y + range * sin(angle)
Beispiel #5
0
  def find_place_for_mark( self, mark, resolution=30):
    """resolution says if the angles should be somehow 'rounded', it is given in degrees;
    see geometry.point_on_circle for a similar thing"""
    mark_name, mark_class = self._mark_to_name_and_class( mark)

    # deal with marks centered
    if mark_class.meta__mark_positioning == 'atom':
      return self.x, self.y

    # deal with statically positioned marks
    if mark_class.meta__mark_positioning == 'righttop':
      bbox = self.bbox()
      return bbox[2]+2, bbox[1]
    
    # deal with marks in linear_form
    if self.is_part_of_linear_fragment():
      if mark_name == "atom_number":
        bbox = self.bbox()
        return int( self.x-0.5*self.font_size), bbox[1]-2
    

    if not self.show:
      dist = 5 + round( mark_class.standard_size / 2)
    else:
      dist = 0.75*self.font_size + round( mark_class.standard_size / 2)

    atms = self.get_neighbors()
    x, y = self.get_xy()

    # special cases
    if not atms:
      # single atom molecule
      if self.show_hydrogens and self.pos == "center-first":
        return x -dist, y-3
      else:
        return x +dist, y-3

    # normal case
    coords = [(a.x,a.y) for a in atms]
    # we have to take marks into account
    [coords.append( (m.x, m.y)) for m in self.marks]
    # hydrogen positioning is also important
    if self.show_hydrogens and self.show:
      if self.pos == 'center-last':
        coords.append( (x-10,y))
      else:
        coords.append( (x+10,y))
    # now we can compare the angles
    angles = [geometry.clockwise_angle_from_east( x1-x, y1-y) for x1,y1 in coords]
    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]) / 2

    # we calculate the distance here again as it is anisotropic (depends on direction)
    bbox = list( misc.normalize_coords( self.bbox()))
    x0, y0 = geometry.point_on_circle( x, y, 500, direction=(cos(angle), sin( angle)), resolution=resolution)
    x1, y1 = geometry.intersection_of_line_and_rect( (x,y,x0,y0), bbox, round_edges=0)
    dist = geometry.point_distance( x, y, x1, y1) + round( mark_class.standard_size / 2)
    # //

    
    retx, rety = geometry.point_on_circle( x, y, dist, direction=(cos(angle), sin( angle)), resolution=resolution)

    # in visible text x,y are not on the center, therefore we compensate for it
#    if self.show:
#      y -= 0.166 * self.font_size
    
    return retx, rety
Beispiel #6
0
 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
Beispiel #7
0
    def find_place_for_mark(self, mark, resolution=30):
        """resolution says if the angles should be somehow 'rounded', it is given in degrees;
    see geometry.point_on_circle for a similar thing"""
        mark_name, mark_class = self._mark_to_name_and_class(mark)

        # deal with marks centered
        if mark_class.meta__mark_positioning == 'atom':
            return self.x, self.y

        # deal with statically positioned marks
        if mark_class.meta__mark_positioning == 'righttop':
            bbox = self.bbox()
            return bbox[2] + 2, bbox[1]

        # deal with marks in linear_form
        if self.is_part_of_linear_fragment():
            if mark_name == "atom_number":
                bbox = self.bbox()
                return int(self.x - 0.5 * self.font_size), bbox[1] - 2

        if not self.show:
            dist = 5 + round(mark_class.standard_size / 2)
        else:
            dist = 0.75 * self.font_size + round(mark_class.standard_size / 2)

        atms = self.get_neighbors()
        x, y = self.get_xy()

        # special cases
        if not atms:
            # single atom molecule
            if self.show_hydrogens and self.pos == "center-first":
                return x - dist, y - 3
            else:
                return x + dist, y - 3

        # normal case
        coords = [(a.x, a.y) for a in atms]
        # we have to take marks into account
        [coords.append((m.x, m.y)) for m in self.marks]
        # hydrogen positioning is also important
        if self.show_hydrogens and self.show:
            if self.pos == 'center-last':
                coords.append((x - 10, y))
            else:
                coords.append((x + 10, y))
        # now we can compare the angles
        angles = [
            geometry.clockwise_angle_from_east(x1 - x, y1 - y)
            for x1, y1 in coords
        ]
        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]) / 2

        # we calculate the distance here again as it is anisotropic (depends on direction)
        bbox = list(misc.normalize_coords(self.bbox()))
        x0, y0 = geometry.point_on_circle(x,
                                          y,
                                          500,
                                          direction=(cos(angle), sin(angle)),
                                          resolution=resolution)
        x1, y1 = geometry.intersection_of_line_and_rect((x, y, x0, y0),
                                                        bbox,
                                                        round_edges=0)
        dist = geometry.point_distance(x, y, x1, y1) + round(
            mark_class.standard_size / 2)
        # //

        retx, rety = geometry.point_on_circle(x,
                                              y,
                                              dist,
                                              direction=(cos(angle),
                                                         sin(angle)),
                                              resolution=resolution)

        # in visible text x,y are not on the center, therefore we compensate for it
        #    if self.show:
        #      y -= 0.166 * self.font_size

        return retx, rety