예제 #1
0
def bridge(coords, ring, isec):
    r = deque(ring)
    while r[0] not in isec or r[-1] in isec:
        r.rotate()
    v = r.popleft()
    u = None
    while True:
        p = r.popleft()
        if p in isec:
            u = p
        else:
            break
    r.appendleft(p)  # TODO: refactor
    ux, uy, ua, _ = coords[u]
    vx, vy, va, _ = coords[v]
    utov = gm.vector((ux, uy), (vx, vy))
    utovang = gm.rad(math.atan2(utov[1], utov[0]))
    dist = gm.distance((ux, uy), (vx, vy))
    step, angle = bridge_angle(dist, len(r))
    angle += utovang
    prev = u
    coords[prev][2] = gm.rad(utovang + math.pi)  # reverse
    while r:
        tail = r.popleft()
        x, y, a, _ = coords[prev]
        coords[tail] = [x + math.cos(angle), y + math.sin(angle),
                        gm.rad(a + step), 1]
        angle += step
        prev = tail
예제 #2
0
 def draw_dashed_wedge(self, head, tail, color):
     width = self.displaymlb * 0.2
     t1 = m_seg(tail, head, math.pi / -2, width / 2)[0]
     t2 = m_seg(tail, head, math.pi / 2, width / 2)[0]
     step_num = 7
     for i in range(step_num):
         step = distance(head, tail) / step_num * i
         trim = 1 / step_num * i
         tp1, tp2 = p_seg(t1, t2, True, step, trim)
         tpx, tpy = [tuple(p) for p in zip(tp1, tp2)]
         self.ax.add_line(mpl.lines.Line2D(
             tpx, tpy, c=color, lw=1.5, clip_on=False
         ))
예제 #3
0
 def draw_dashed_wedge(self, head, tail, color):
     width = self.displaymlb * 0.2
     tmpl = '<line x1="{}" y1="{}" x2="{}" y2="{}" stroke="{}" />\n'
     t1 = m_seg(tail, head, math.pi / -2, width / 2)[0]
     t2 = m_seg(tail, head, math.pi / 2, width / 2)[0]
     step_num = 7
     for i in range(step_num):
         step = distance(head, tail) / step_num * i
         trim = 1 / step_num * i
         tp1, tp2 = p_seg(t1, t2, True, step, trim)
         self._elems.append(
             tmpl.format(round(tp1[0], 2), round(tp1[1], 2),
                         round(tp2[0], 2), round(tp2[1], 2), color))
예제 #4
0
 def _draw_dashed_wedge(self, head, tail, width, color=(0, 0, 0)):
     chead = self._convert(head)
     ctail = self._convert(tail)
     b1 = m_seg(ctail, chead, math.pi / -2, width / 2)[0]
     b2 = m_seg(ctail, chead, math.pi / 2, width / 2)[0]
     pen = QtGui.QPen(QtGui.QColor(*color), 1, QtCore.Qt.SolidLine)
     self.painter.setPen(pen)
     step_num = 6
     # TODO: adjust step number
     for i in range(step_num):
         step = distance(chead, ctail) / step_num * i
         trim = 1 / step_num * i
         bp1, bp2 = p_seg(b1, b2, True, step, trim)
         qp1 = QtCore.QPointF(*bp1)
         qp2 = QtCore.QPointF(*bp2)
         self.painter.drawLine(qp1, qp2)
예제 #5
0
파일: helper.py 프로젝트: mrauha/chorus
def scale_and_center(mol):
    """Center and Scale molecule 2D coordinates.
    This method changes mol coordinates directly to center but not scale.
    This method returns width, height and MLB(median length of bond)
    and scaling will be done by drawer method with these values.

    Returns:
        width: float
        height: float
        mlb: median length of bond
    """
    cnt = mol.atom_count()
    if cnt < 2:
        mol.size2d = (0, 0, 1)
        mol.descriptors.add("ScaleAndCenter")
        return
    xs = []
    ys = []
    for _, atom in mol.atoms_iter():
        xs.append(atom.coords[0])
        ys.append(atom.coords[1])
    xmin, xmax = (min(xs), max(xs))
    ymin, ymax = (min(ys), max(ys))
    width = xmax - xmin
    height = ymax - ymin
    x_offset = width / 2 + xmin
    y_offset = height / 2 + ymin
    dists = []
    for u, v, _ in mol.bonds_iter():
        dists.append(geometry.distance(mol.atom(u).coords, mol.atom(v).coords))
    try:
        mlb = statistics.median(dists)
    except statistics.StatisticsError:
        # No connection
        mlb = math.sqrt(max([width, height]) / cnt)  # empirical
    if not mlb:  # Many of connected atoms are overlapped
        mol.size2d = (0, 0, 1)
        mol.descriptors.add("ScaleAndCenter")
        return
    # Centering
    for _, atom in mol.atoms_iter():
        atom.coords = (atom.coords[0] - x_offset, atom.coords[1] - y_offset)
    mol.size2d = (width, height, mlb)
    mol.descriptors.add("ScaleAndCenter")
예제 #6
0
 def test_length(self):
     o = (2, 2)
     p1 = (5, 6)
     p2 = (2, 2)
     self.assertEqual(gm.distance(p1, o), 5)
     self.assertEqual(gm.distance(p2, o), 0)
예제 #7
0
def draw(canvas, mol):
    """Draw molecule structure image.

    Args:
        canvas: draw.drawable.Drawable
        mol: model.graphmol.Compound
    """
    mol.require("ScaleAndCenter")
    mlb = mol.size2d[2]
    if not mol.atom_count():
        return
    bond_type_fn = {
        1: {
            0: single_bond,
            1: wedged_single,
            2: dashed_wedged_single,
            3: wave_single,
        },
        2: {
            0: cw_double,
            1: counter_cw_double,
            2: double_bond,
            3: cross_double
        },
        3: {
            0: triple_bond
        }
    }
    # Draw bonds
    for u, v, bond in mol.bonds_iter():
        if not bond.visible:
            continue
        if (u < v) == bond.is_lower_first:
            f, s = (u, v)
        else:
            s, f = (u, v)
        p1 = mol.atom(f).coords
        p2 = mol.atom(s).coords
        if p1 == p2:
            continue  # avoid zero division
        if mol.atom(f).visible:
            p1 = gm.t_seg(p1, p2, F_AOVL, 2)[0]
        if mol.atom(s).visible:
            p2 = gm.t_seg(p1, p2, F_AOVL, 1)[1]
        color1 = mol.atom(f).color
        color2 = mol.atom(s).color
        bond_type_fn[bond.order][bond.type](canvas, p1, p2, color1, color2,
                                            mlb)

    # Draw atoms
    for n, atom in mol.atoms_iter():
        if not atom.visible:
            continue
        p = atom.coords
        color = atom.color
        # Determine text direction
        if atom.H_count:
            cosnbrs = []
            hrzn = (p[0] + 1, p[1])
            for nbr in mol.graph.neighbors(n):
                pnbr = mol.atom(nbr).coords
                try:
                    cosnbrs.append(
                        gm.dot_product(hrzn, pnbr, p) / gm.distance(p, pnbr))
                except ZeroDivisionError:
                    pass
            if not cosnbrs or min(cosnbrs) > 0:
                # [atom]< or isolated node(ex. H2O, HCl)
                text = atom.formula_html(True)
                canvas.draw_text(p, text, color, "right")
                continue
            elif max(cosnbrs) < 0:
                # >[atom]
                text = atom.formula_html()
                canvas.draw_text(p, text, color, "left")
                continue
        # -[atom]- or no hydrogens
        text = atom.formula_html()
        canvas.draw_text(p, text, color, "center")