Esempio n. 1
0
 def _draw_second_line( self, coords):
   my_x1, my_y1 = self.atom1.get_xy()
   my_x2, my_y2 = self.atom2.get_xy()
   my_coords = (my_x1,my_y1,my_x2,my_y2)
   x, y, x0, y0 = coords
   # shortening of the second bond
   dx = x-x0
   dy = y-y0
   if self.center:
     _k = 0
   else:
     _k = (1-self.double_length_ratio)/2
   x, y, x0, y0 = x-_k*dx, y-_k*dy, x0+_k*dx, y0+_k*dy
   # shift according to the bonds arround
   side = geometry.on_which_side_is_point( my_coords, (x,y))
   for atom in (self.atom1,self.atom2):
     second_atom = atom is self.atom1 and self.atom2 or self.atom1
     neighs = [n for n in atom.neighbors if geometry.on_which_side_is_point( my_coords, n.get_xy())==side and n is not second_atom]
     for n in neighs:
       dist2 = _k*geometry.point_distance(*my_coords)*geometry.on_which_side_is_point((atom.x, atom.y, n.x, n.y), (second_atom.x, second_atom.y))
       xn1, yn1, xn2, yn2 = geometry.find_parallel( atom.x, atom.y, n.x, n.y, dist2)
       xp,yp,parallel,online = geometry.intersection_of_two_lines( x,y,x0,y0,xn1,yn1,xn2,yn2)
       if not parallel:
         if not geometry.is_point_beween_points_of_line( (x,y,x0,y0),(xp,yp)):
           # only shorten the line - do not elongate it
           continue
         if geometry.point_distance( atom.x,atom.y,x,y) < geometry.point_distance( atom.x,atom.y,x0,y0):
           x,y = xp, yp
         else:
           x0,y0 = xp, yp
       else:
         # parallel
         pass
   return [self._create_line_with_transform( (x, y, x0, y0), width=self.line_width, fill=self.line_color)]
Esempio n. 2
0
 def _draw_second_line( self, coords):
   my_x1, my_y1 = self.atom1.get_xy()
   my_x2, my_y2 = self.atom2.get_xy()
   my_coords = (my_x1,my_y1,my_x2,my_y2)
   x, y, x0, y0 = coords
   # shortening of the second bond
   dx = x-x0
   dy = y-y0
   if self.center:
     _k = 0
   else:
     _k = (1-self.double_length_ratio)/2
   x, y, x0, y0 = x-_k*dx, y-_k*dy, x0+_k*dx, y0+_k*dy
   # shift according to the bonds arround
   side = geometry.on_which_side_is_point( my_coords, (x,y))
   for atom in (self.atom1,self.atom2):
     second_atom = atom is self.atom1 and self.atom2 or self.atom1
     neighs = [n for n in atom.neighbors if geometry.on_which_side_is_point( my_coords, n.get_xy())==side and n is not second_atom]
     for n in neighs:
       dist2 = _k*geometry.point_distance(*my_coords)*geometry.on_which_side_is_point((atom.x, atom.y, n.x, n.y), (second_atom.x, second_atom.y))
       xn1, yn1, xn2, yn2 = geometry.find_parallel( atom.x, atom.y, n.x, n.y, dist2)
       xp,yp,parallel,online = geometry.intersection_of_two_lines( x,y,x0,y0,xn1,yn1,xn2,yn2)
       if not parallel:
         if not geometry.is_point_beween_points_of_line( (x,y,x0,y0),(xp,yp)):
           # only shorten the line - do not elongate it
           continue
         if geometry.point_distance( atom.x,atom.y,x,y) < geometry.point_distance( atom.x,atom.y,x0,y0):
           x,y = xp, yp
         else:
           x0,y0 = xp, yp
       else:
         # parallel
         pass
   return [self._create_line_with_transform( (x, y, x0, y0), width=self.line_width, fill=self.line_color)]
Esempio n. 3
0
  def create_mark( self, mark='radical', angle='auto', draw=1, angle_resolution=1):
    """creates the mark, does not care about the chemical meaning of this"""
    # decide where to put the mark
    mark_name, mark_class = self._mark_to_name_and_class( mark)
    if angle == 'auto':
      x, y = self.find_place_for_mark( mark, resolution=angle_resolution)
    else:
      if not self.show:
        dist = 5 + round( mark_class.standard_size / 2)
      else:
        bbox = self.bbox()
        x2 = self.x + round( cos( angle) *1000)
        y2 = self.y + round( sin( angle) *1000)
        x1, y1 = geometry.intersection_of_line_and_rect( (self.x,self.y,x2,y2), bbox, round_edges=0)      
        dist = geometry.point_distance( self.x, self.y, x1, y1) + round( mark_class.standard_size / 2)
        
      x = self.x + round( cos( angle) *dist)
      y = self.y + round( sin( angle) *dist)
      #ang = angle

    m = mark_class( self, x, y, auto=(angle=='auto'))
    if draw:
      m.draw()
    self.marks.add( m)
    return m
Esempio n. 4
0
    def create_mark(self,
                    mark='radical',
                    angle='auto',
                    draw=1,
                    angle_resolution=1):
        """creates the mark, does not care about the chemical meaning of this"""
        # decide where to put the mark
        mark_name, mark_class = self._mark_to_name_and_class(mark)
        if angle == 'auto':
            x, y = self.find_place_for_mark(mark, resolution=angle_resolution)
        else:
            if not self.show:
                dist = 5 + round(mark_class.standard_size / 2)
            else:
                bbox = self.bbox()
                x2 = self.x + round(cos(angle) * 1000)
                y2 = self.y + round(sin(angle) * 1000)
                x1, y1 = geometry.intersection_of_line_and_rect(
                    (self.x, self.y, x2, y2), bbox, round_edges=0)
                dist = geometry.point_distance(self.x, self.y, x1, y1) + round(
                    mark_class.standard_size / 2)

            x = self.x + round(cos(angle) * dist)
            y = self.y + round(sin(angle) * dist)
            #ang = angle

        m = mark_class(self, x, y, auto=(angle == 'auto'))
        if draw:
            m.draw()
        self.marks.add(m)
        return m
Esempio n. 5
0
  def _where_to_draw_from_and_to( self):
    x1, y1 = self.atom1.get_xy()
    x2, y2 = self.atom2.get_xy()
    # at first check if the bboxes are not overlapping
    bbox1 = list( misc.normalize_coords( self.atom1.bbox( substract_font_descent=True)))
    bbox2 = list( misc.normalize_coords( self.atom2.bbox( substract_font_descent=True)))
    if geometry.do_rectangles_intersect( bbox1, bbox2):
      return None
    # then we continue with computation
    if self.atom1.show:
      x1, y1 = geometry.intersection_of_line_and_rect( (x1,y1,x2,y2), bbox1, round_edges=0)
    if self.atom2.show:
      x2, y2 = geometry.intersection_of_line_and_rect( (x1,y1,x2,y2), bbox2, round_edges=0)

    if geometry.point_distance( x1, y1, x2, y2) <= 1.0:
      return None
    else:
      return (x1, y1, x2, y2)
Esempio n. 6
0
  def _where_to_draw_from_and_to( self):
    x1, y1 = self.atom1.get_xy()
    x2, y2 = self.atom2.get_xy()
    # at first check if the bboxes are not overlapping
    bbox1 = list( misc.normalize_coords( self.atom1.bbox( substract_font_descent=True)))
    bbox2 = list( misc.normalize_coords( self.atom2.bbox( substract_font_descent=True)))
    if geometry.do_rectangles_intersect( bbox1, bbox2):
      return None
    # then we continue with computation
    if self.atom1.show:
      x1, y1 = geometry.intersection_of_line_and_rect( (x1,y1,x2,y2), bbox1, round_edges=0)
    if self.atom2.show:
      x2, y2 = geometry.intersection_of_line_and_rect( (x1,y1,x2,y2), bbox2, round_edges=0)

    if geometry.point_distance( x1, y1, x2, y2) <= 1.0:
      return None
    else:
      return (x1, y1, x2, y2)
Esempio n. 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
Esempio n. 8
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