| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 | #!/usr/bin/env python## This code is part of Grandalf# Copyright (C) 2008 Axel Tillequin (bdcht3@gmail.com) and others# published under GPLv2 license or EPLv1 license# Contributor(s): Axel Tillequin, Fabio Zadroznyfrom .poset import *from .dot import *from math import atan2, sqrtfrom random import SystemRandom# ------------------------------------------------------------------------------def intersect2lines(xy1, xy2, xy3, xy4):    (x1, y1) = xy1    (x2, y2) = xy2    (x3, y3) = xy3    (x4, y4) = xy4    b = (x2 - x1, y2 - y1)    d = (x4 - x3, y4 - y3)    det = b[0] * d[1] - b[1] * d[0]    if det == 0:        return None    c = (x3 - x1, y3 - y1)    t = float(c[0] * b[1] - c[1] * b[0]) / (det * 1.0)    if t < 0.0 or t > 1.0:        return None    t = float(c[0] * d[1] - c[1] * d[0]) / (det * 1.0)    if t < 0.0 or t > 1.0:        return None    x = x1 + t * b[0]    y = y1 + t * b[1]    return (x, y)# ------------------------------------------------------------------------------#  intersectR returns the intersection point between the Rectangle#  (w,h) that characterize the view object and the line that goes#  from the views' object center to the 'topt' point.def intersectR(view, topt):    # we compute intersection in local views' coord:    # center of view is obviously :    x1, y1 = 0, 0    # endpoint in view's coord:    x2, y2 = topt[0] - view.xy[0], topt[1] - view.xy[1]    # bounding box:    bbx2 = view.w // 2    bbx1 = -bbx2    bby2 = view.h // 2    bby1 = -bby2    # all 4 segments of the bb:    S = [        ((x1, y1), (x2, y2), (bbx1, bby1), (bbx2, bby1)),        ((x1, y1), (x2, y2), (bbx2, bby1), (bbx2, bby2)),        ((x1, y1), (x2, y2), (bbx1, bby2), (bbx2, bby2)),        ((x1, y1), (x2, y2), (bbx1, bby2), (bbx1, bby1)),    ]    # check intersection with each seg:    for segs in S:        xy = intersect2lines(*segs)        if xy != None:            x, y = xy            # return global coord:            x += view.xy[0]            y += view.xy[1]            return (x, y)    # there can't be no intersection unless the endpoint was    # inside the bb !    raise ValueError(        "no intersection found (point inside ?!). view: %s topt: %s" % (view, topt)    )# ------------------------------------------------------------------------------def getangle(p1, p2):    x1, y1 = p1    x2, y2 = p2    theta = atan2(y2 - y1, x2 - x1)    return theta# ------------------------------------------------------------------------------def median_wh(views):    mw = [v.w for v in views]    mh = [v.h for v in views]    mw.sort()    mh.sort()    return (mw[len(mw) // 2], mh[len(mh) // 2])# ------------------------------------------------------------------------------try:    from numpy import array, matrix, cos, sin    has_numpy = Trueexcept ImportError:    has_numpy = False    from math import cos, sin, pi    from .linalg import array, matrix#  rand_ortho1 returns a numpy.array representing#  a random normalized n-dimension vector orthogonal to (1,1,1,...,1).def rand_ortho1(n):    r = SystemRandom()    pos = [r.random() for x in range(n)]    s = sum(pos)    v = array(pos, dtype=float) - (s / float(n))    norm = sqrt(sum(v * v))    return v / norm# ------------------------------------------------------------------------------#  intersectC returns the intersection point between the Circle#  of radius r and centered on views' position with the line#  to the 'topt' point.def intersectC(view, r, topt):    theta = getangle(view.xy, topt)    x = int(cos(theta) * r)    y = int(sin(theta) * r)    return (x, y)# ------------------------------------------------------------------------------#  setcurve returns the spline curve that path through the list of points P.#  The spline curve is a list of cubic bezier curves (nurbs) that have#  matching tangents at their extreme points.#  The method considered here is taken from "The NURBS book" (Les A. Piegl,#  Wayne Tiller, Springer, 1997) and implements a local interpolation rather#  than a global interpolation.def setcurve(e, pts, tgs=None):    P = list(map(array, pts))    n = len(P)    # tangent estimation    if tgs:        assert len(tgs) == n        T = list(map(array, tgs))        Q = [P[k + 1] - P[k] for k in range(0, n - 1)]    else:        Q, T = tangents(P, n)    splines = []    for k in range(n - 1):        t = T[k] + T[k + 1]        a = 16.0 - (t.dot(t))        b = 12.0 * (Q[k].dot(t))        c = -36.0 * Q[k].dot(Q[k])        D = (b * b) - 4.0 * a * c        assert D >= 0        sd = sqrt(D)        s1, s2 = (-b - sd) / (2.0 * a), (-b + sd) / (2.0 * a)        s = s2        if s1 >= 0:            s = s1        C0 = tuple(P[k])        C1 = tuple(P[k] + (s / 3.0) * T[k])        C2 = tuple(P[k + 1] - (s / 3.0) * T[k + 1])        C3 = tuple(P[k + 1])        splines.append([C0, C1, C2, C3])    return splines# ------------------------------------------------------------------------------def tangents(P, n):    assert n >= 2    Q = []    T = []    for k in range(0, n - 1):        q = P[k + 1] - P[k]        t = q / sqrt(q.dot(q))        Q.append(q)        T.append(t)    T.append(t)    return (Q, T)# ------------------------------------------------------------------------------def setroundcorner(e, pts):    P = list(map(array, pts))    n = len(P)    Q, T = tangents(P, n)    c0 = P[0]    t0 = T[0]    k0 = 0    splines = []    k = 1    while k < n:        z = abs(t0[0] * T[k][1] - (t0[1] * T[k][0]))        if z < 1.0e-6:            k += 1            continue        if (k - 1) > k0:            splines.append([c0, P[k - 1]])        if (k + 1) < n:            splines.extend(setcurve(e, [P[k - 1], P[k + 1]], tgs=[T[k - 1], T[k + 1]]))        else:            splines.extend(setcurve(e, [P[k - 1], P[k]], tgs=[T[k - 1], T[k]]))            break        if (k + 2) < n:            c0 = P[k + 1]            t0 = T[k + 1]            k0 = k + 1            k += 2        else:            break    return splines or [[P[0], P[-1]]]# ------------------------------------------------------------------------------def new_point_at_distance(pt, distance, angle):    # angle in radians    distance = float(distance)    x, y = pt[0], pt[1]    x += distance * cos(angle)    y += distance * sin(angle)    return x, y
 |