"""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))