def resize( self, coords, fix=()): if not fix: x1, y1, x2, y2 = misc.normalize_coords( coords) dx = x2 - x1 dy = y2 - y1 d = (abs( dx) + abs( dy))/2 self.coords = (x1, y1, x1+d, y1+d) else: x1, y1, x2, y2 = coords dx = (fix[0] - x1) or (fix[0] - x2) dy = (fix[1] - y2) or (fix[1] - y1) d = (abs( dx) + abs( dy))/2 self.coords = misc.normalize_coords( (fix[0], fix[1], x1-(d*misc.signum( dx) or d), y1-( d*misc.signum( dy) or d))) self.paper.coords( self.item, self.coords)
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)
def intersection_of_line_and_rect(line, rect, round_edges=0): """finds a point where a line and a rectangle intersect, both are given as lists of len == 4""" lx0, ly0, lx1, ly1 = map(float, line) rx0, ry0, rx1, ry1 = map(float, normalize_coords(rect)) # find which end of line is in the rect and reverse the line if needed if (lx0 > rx0) and (lx0 < rx1) and (ly0 > ry0) and (ly0 < ry1): lx0, lx1 = lx1, lx0 ly0, ly1 = ly1, ly0 # the computation itself ldx = lx1 - lx0 ldy = ly1 - ly0 if abs(ldx) > 0.0001: # we calculate using y = f(x) k = ldy / ldx q = ly0 - k * lx0 if ldx < 0: xx = rx1 else: xx = rx0 xy = k * xx + q # the result must be in the rectangle boundaries # but sometimes is not because rounding problems if not ry0 <= xy <= ry1: xx = lx0 xy = ly0 else: xx = lx0 xy = ly0 if abs(ldy) > 0.0001: # we calculate using x = f(y) k = ldx / ldy q = lx0 - k * ly0 if ldy < 0: yy = ry1 else: yy = ry0 yx = k * yy + q # the result must be in the rectangle boundaries # but sometimes is not because rounding problems if not rx0 <= yx <= rx1: yy = ly0 yx = lx0 else: yy = ly0 yx = lx0 if point_distance(lx0, ly0, xx, xy) < point_distance(lx0, ly0, yx, yy): return (yx, yy) else: return (xx, xy)
def intersection_of_line_and_rect( line, rect, round_edges=0): """finds a point where a line and a rectangle intersect, both are given as lists of len == 4""" lx0, ly0, lx1, ly1 = map( float, line) rx0, ry0, rx1, ry1 = map( float, normalize_coords( rect)) # find which end of line is in the rect and reverse the line if needed if (lx0 > rx0) and (lx0 < rx1) and (ly0 > ry0) and (ly0 < ry1): lx0, lx1 = lx1, lx0 ly0, ly1 = ly1, ly0 # the computation itself ldx = lx1 - lx0 ldy = ly1 - ly0 if abs( ldx) > 0.0001: # we calculate using y = f(x) k = ldy/ldx q = ly0 - k*lx0 if ldx < 0: xx = rx1 else: xx = rx0 xy = k*xx + q # the result must be in the rectangle boundaries # but sometimes is not because rounding problems if not ry0 <= xy <= ry1: xx = lx0 xy = ly0 else: xx = lx0 xy = ly0 if abs( ldy) > 0.0001: # we calculate using x = f(y) k = ldx/ldy q = lx0 - k*ly0 if ldy < 0: yy = ry1 else: yy = ry0 yx = k*yy + q # the result must be in the rectangle boundaries # but sometimes is not because rounding problems if not rx0 <= yx <= rx1: yy = ly0 yx = lx0 else: yy = ly0 yx = lx0 if point_distance( lx0, ly0, xx, xy) < point_distance( lx0, ly0, yx, yy): return (yx, yy) else: return (xx, xy)
def get_fix(self): """returns the coords that should be fixed if we now start to drag the selected corner""" fix = [0, 0] self.coords = misc.normalize_coords(self.coords) if self._active_item in (self._lt, self._lb): fix[0] = self.coords[2] else: fix[0] = self.coords[0] if self._active_item in (self._lt, self._rt): fix[1] = self.coords[3] else: fix[1] = self.coords[1] return fix
def get_fix( self): """Return coords that should be fixed if we now drag selected corner. """ fix = [0,0] self.coords = misc.normalize_coords( self.coords) if self._active_item in (self._lt, self._lb): fix[0] = self.coords[2] else: fix[0] = self.coords[0] if self._active_item in (self._lt, self._rt): fix[1] = self.coords[3] else: fix[1] = self.coords[1] return fix
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
def resize( self, coords, fix=()): self.coords = misc.normalize_coords( coords) self.paper.coords( self.item, self.coords)
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