| 
 | 1 | +"""  | 
 | 2 | +    Cone{T}(origin::Point3, tip::Point3, radius)  | 
 | 3 | +
  | 
 | 4 | +A Cone is a cylinder where one end has a radius of 0. It is defined by an  | 
 | 5 | +`origin` with a finite `radius` which linearly decreases to 0 at the `tip`.  | 
 | 6 | +"""  | 
 | 7 | +struct Cone{T} <: GeometryPrimitive{3, T}  | 
 | 8 | +    origin::Point3{T}  | 
 | 9 | +    tip::Point3{T}  | 
 | 10 | +    radius::T  | 
 | 11 | +end  | 
 | 12 | + | 
 | 13 | +function Cone(origin::Point3{T1}, tip::Point3{T2}, radius::T3) where {T1, T2, T3}  | 
 | 14 | +    T = promote_type(T1, T2, T3)  | 
 | 15 | +    return Cone{T}(origin, tip, radius)  | 
 | 16 | +end  | 
 | 17 | + | 
 | 18 | +origin(c::Cone) = c.origin  | 
 | 19 | +extremity(c::Cone) = c.tip  | 
 | 20 | +radius(c::Cone) = c.radius  | 
 | 21 | +height(c::Cone) = norm(c.tip - c.origin)  | 
 | 22 | +direction(c::Cone) = (c.tip .- c.origin) ./ height(c)  | 
 | 23 | + | 
 | 24 | +function rotation(c::Cone{T}) where {T}  | 
 | 25 | +    d3 = direction(c)  | 
 | 26 | +    u = Vec{3, T}(d3[1], d3[2], d3[3])  | 
 | 27 | +    if abs(u[1]) > 0 || abs(u[2]) > 0  | 
 | 28 | +        v = Vec{3, T}(u[2], -u[1], T(0))  | 
 | 29 | +    else  | 
 | 30 | +        v = Vec{3, T}(T(0), -u[3], u[2])  | 
 | 31 | +    end  | 
 | 32 | +    v = normalize(v)  | 
 | 33 | +    w = Vec{3, T}(u[2] * v[3] - u[3] * v[2], -u[1] * v[3] + u[3] * v[1],  | 
 | 34 | +                  u[1] * v[2] - u[2] * v[1])  | 
 | 35 | +    return Mat{3, 3, T}(v..., w..., u...)  | 
 | 36 | +end  | 
 | 37 | + | 
 | 38 | +function coordinates(c::Cone{T}, nvertices=30) where {T}  | 
 | 39 | +    nvertices += isodd(nvertices)  | 
 | 40 | +    nhalf = div(nvertices, 2)  | 
 | 41 | + | 
 | 42 | +    R = rotation(c)  | 
 | 43 | +    step = 2pi / nhalf  | 
 | 44 | + | 
 | 45 | +    ps = Vector{Point3{T}}(undef, nhalf + 2)  | 
 | 46 | +    for i in 1:nhalf  | 
 | 47 | +        phi = (i-1) * step  | 
 | 48 | +        ps[i] = R * Point3{T}(c.radius * cos(phi), c.radius * sin(phi), 0) + c.origin  | 
 | 49 | +    end  | 
 | 50 | +    ps[end-1] = c.tip  | 
 | 51 | +    ps[end] = c.origin  | 
 | 52 | + | 
 | 53 | +    return ps  | 
 | 54 | +end  | 
 | 55 | + | 
 | 56 | +function normals(c::Cone, nvertices = 30)  | 
 | 57 | +    nvertices += isodd(nvertices)  | 
 | 58 | +    nhalf = div(nvertices, 2)  | 
 | 59 | + | 
 | 60 | +    R = rotation(c)  | 
 | 61 | +    step = 2pi / nhalf  | 
 | 62 | + | 
 | 63 | +    ns = Vector{Vec3f}(undef, nhalf + 2)  | 
 | 64 | +    # shell at origin  | 
 | 65 | +    # normals are angled in z direction due to change in radius (from radius to 0)  | 
 | 66 | +    # This can be calculated from triangles  | 
 | 67 | +    z = radius(c) / height(c)  | 
 | 68 | +    norm = 1.0 / sqrt(1 + z*z)  | 
 | 69 | +    for i in 1:nhalf  | 
 | 70 | +        phi = (i-1) * step  | 
 | 71 | +        ns[i] = R * (norm * Vec3f(cos(phi), sin(phi), z))  | 
 | 72 | +    end  | 
 | 73 | + | 
 | 74 | +    # tip - this is undefined / should be all ring angles at once  | 
 | 75 | +    # for rendering it is useful to define this as Vec3f(0), because tip normal  | 
 | 76 | +    # has no useful value to contribute to the interpolated fragment normal  | 
 | 77 | +    ns[end-1] = Vec3f(0)  | 
 | 78 | + | 
 | 79 | +    # cap  | 
 | 80 | +    ns[end] = Vec3f(normalize(c.origin - c.tip))  | 
 | 81 | + | 
 | 82 | +    return ns  | 
 | 83 | +end  | 
 | 84 | + | 
 | 85 | +function faces(::Cone, facets=30)  | 
 | 86 | +    nvertices = facets + isodd(facets)  | 
 | 87 | +    nhalf = div(nvertices, 2)  | 
 | 88 | + | 
 | 89 | +    faces = Vector{GLTriangleFace}(undef, nvertices)  | 
 | 90 | + | 
 | 91 | +    # shell  | 
 | 92 | +    for i in 1:nhalf  | 
 | 93 | +        faces[i] = GLTriangleFace(i, mod1(i+1, nhalf), nhalf+1)  | 
 | 94 | +    end  | 
 | 95 | + | 
 | 96 | +    # cap  | 
 | 97 | +    for i in 1:nhalf  | 
 | 98 | +        faces[i+nhalf] = GLTriangleFace(i, mod1(i+1, nhalf), nhalf+2)  | 
 | 99 | +    end  | 
 | 100 | + | 
 | 101 | +    return faces  | 
 | 102 | +end  | 
0 commit comments