verify_shapes.py

Preview

Code · 2.5 KiB
"""Check smoothness, seam closure and sampled self-intersections for every shape."""
import json
import numpy as np
from geometry import curve_points
from shapes import SHAPES,shape


def verify():
    report={}
    for name in SHAPES:
        p=np.asarray(shape(name,(0,0),1))
        assert np.isfinite(p).all() and (len(p)-1)%3==0,name
        assert np.allclose(p[0],p[-1],atol=1e-12),name
        spans=np.array([p[i:i+4] for i in range(0,len(p)-1,3)])
        first=3*(spans[:,1]-spans[:,0]);last=3*(spans[:,3]-spans[:,2])
        second_start=6*(spans[:,2]-2*spans[:,1]+spans[:,0])
        second_end=6*(spans[:,3]-2*spans[:,2]+spans[:,1])
        tangent_error=float(np.max(abs(last-np.roll(first,-1,axis=0))))
        curvature_error=float(np.max(abs(second_end-np.roll(second_start,-1,axis=0))))
        intentional_corners=[]
        if name=='heart':
            # The supplied silhouette calls for a crisp notch and bottom point.
            intentional_corners=[2,5]
            for i in (0,1,3,4):
                a=last[i];b=first[(i+1)%len(first)]
                assert abs(a[0]*b[1]-a[1]*b[0])<1e-12 and a@b>0,name
            assert np.allclose(p[:10]*[-1,1],p[::-1][:10]),name
            assert np.allclose(p[0],[0,-.54]) and np.allclose(p[9],[0,.82]),name
        else:
            assert tangent_error<1e-12 and curvature_error<1e-12,name
        t=np.linspace(0,1,9)[None,:,None]
        speed=3*((1-t)**2*(spans[:,1]-spans[:,0])[:,None]+2*(1-t)*t*(spans[:,2]-spans[:,1])[:,None]+t*t*(spans[:,3]-spans[:,2])[:,None])
        assert np.linalg.norm(speed,axis=-1).min()>1e-6,name
        outline=curve_points(p,count=6)
        # Chunk intersection checks to keep memory bounded for dense sun rays.
        def cross(a,b):return a[...,0]*b[...,1]-a[...,1]*b[...,0]
        c=outline[None,:,:];d=np.roll(outline,-1,axis=0)[None,:,:]
        for start in range(0,len(outline),64):
            a=outline[start:start+64,None,:];b=np.roll(outline,-1,axis=0)[start:start+64,None,:]
            hits=(cross(b-a,c-a)*cross(b-a,d-a)<-1e-14)&(cross(d-c,a-c)*cross(d-c,b-c)<-1e-14)
            assert not hits.any(),name
        report[name]={'cubic_spans':len(spans),'tangent_join_error':tangent_error,'second_derivative_join_error':curvature_error,'intentional_corner_span_ends':intentional_corners,'smooth_join_type':'G1 except designed notch and tip' if name=='heart' else 'C2','closed_curve':True,'nonzero_sampled_span_speed':True,'sampled_self_intersections':0}
    return report

if __name__=='__main__':print(json.dumps(verify(),indent=2))

Files