ContentsFoundations to FrontierBezhig

integration_code/solutions/graphics.py

All lab code. Download this file.

"""W06: triangle coordinates and perspective interpolation, CPU-only."""
import math


def barycentric(point,a,b,c):
    if any(len(p)!=2 or any(not math.isfinite(x) for x in p) for p in (point,a,b,c)):
        raise ValueError("finite two-dimensional points required")
    ux,uy=b[0]-a[0],b[1]-a[1]
    vx,vy=c[0]-a[0],c[1]-a[1]
    px,py=point[0]-a[0],point[1]-a[1]
    determinant=ux*vy-uy*vx
    if not math.isfinite(determinant) or determinant==0:
        raise ValueError("degenerate or unrepresentable triangle")
    beta=(px*vy-py*vx)/determinant
    gamma=(ux*py-uy*px)/determinant
    result=(1-beta-gamma,beta,gamma)
    if not all(math.isfinite(x) for x in result):raise ValueError("nonfinite weights")
    return result


def perspective(weights,w,attributes):
    if len(weights)!=3 or len(w)!=3 or len(attributes)!=3 or not attributes[0]:
        raise ValueError("three vertices and nonempty attributes required")
    width=len(attributes[0])
    if width>64 or any(len(row)!=width for row in attributes):raise ValueError("attribute shape")
    if any(not math.isfinite(x) for x in [*weights,*w,*[v for row in attributes for v in row]]):
        raise ValueError("finite inputs required")
    if any(x<0 for x in weights) or not math.isclose(math.fsum(weights),1.,rel_tol=0.,abs_tol=1e-12):
        raise ValueError("inside-triangle weights summing to one required")
    if any(x<=0 for x in w):raise ValueError("positive clip w required in this bounded lab")
    coefficients=[a/b for a,b in zip(weights,w)]
    denominator=math.fsum(coefficients)
    if not math.isfinite(denominator) or denominator<=0:raise ValueError("invalid denominator")
    result=[math.fsum(c*row[k] for c,row in zip(coefficients,attributes))/denominator
            for k in range(width)]
    if not all(math.isfinite(x) for x in result):raise ValueError("nonfinite attribute")
    return result


if __name__=='__main__':
    print(barycentric((1,1),(0,0),(4,0),(0,4)))
    print(perspective([.5,.25,.25],[1,2,4],[[0],[8],[16]]))