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