Skip to content

Commit

Permalink
Ray3D reflect from Plane
Browse files Browse the repository at this point in the history
  • Loading branch information
islent committed Jul 6, 2024
1 parent dd0b880 commit 75b1175
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 7 deletions.
13 changes: 13 additions & 0 deletions src/PhysicalMeshes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ export
AbstractLine2D, AbstractLine3D,
Line, Line2D,

# Plane
Plane,
coplanar,

# Polygon
Polygon2D, Polygon3D,
polygon_rect, polygon_regular,
isconvex,

# Ray
Ray2D, Ray3D,
intersect,
Expand Down Expand Up @@ -123,6 +132,9 @@ abstract type AbstractLine{T} <: AbstractGeometryType{T} end
abstract type AbstractLine2D{T} <: AbstractLine{T} end
abstract type AbstractLine3D{T} <: AbstractLine{T} end

abstract type AbstractPlane{T} <: AbstractGeometryType{T} end
abstract type AbstractPlane3D{T} <: AbstractPlane{T} end

abstract type AbstractPolygon{T} <: AbstractGeometryType{T} end
abstract type AbstractPolygon2D{T} <: AbstractPolygon{T} end
abstract type AbstractPolygon3D{T} <: AbstractPolygon{T} end
Expand Down Expand Up @@ -156,6 +168,7 @@ include("core/predicates.jl")
include("Sphere.jl")

include("Line.jl")
include("Plane.jl")
include("Polygon.jl")
include("Ray.jl")
include("Cube.jl")
Expand Down
16 changes: 16 additions & 0 deletions src/Plane.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
$(TYPEDEF)
$(TYPEDFIELDS)
"""
struct Plane{T} <: AbstractPlane{T}
a::PVector{T}
b::PVector{T}
c::PVector{T}
end

normal(a,b,c) = normalize(cross(b-a, ustrip(c-a)))
normal(plane::Plane) = normal(plane.a, plane.b, plane.c)

distance(p::AbstractPoint3D, plane::Plane) = abs(dot(normal(plane), p-plane.a))

coplanar(p::AbstractPoint3D, plane::Plane, threshold::Number) = distance(p, plane) <= threshold
95 changes: 93 additions & 2 deletions src/Polygon.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,104 @@ $(TYPEDEF)
$(TYPEDFIELDS)
"""
struct Polygon2D{T} <: AbstractPolygon2D{T}
points
vertices
end

function Polygon2D(vertices)
if length(vertices) < 3
error("Number of vertices less than 3, a concrete polygon should have more than 2 vertices")
end

Polygon2D(vertices)
end

"""
$(TYPEDEF)
$(TYPEDFIELDS)
"""
struct Polygon3D{T} <: AbstractPolygon3D{T}
points
vertices
end

function Polygon3D(vertices)
if length(vertices) < 3
error("Number of vertices less than 3, a concrete polygon should have more than 2 vertices")
end

if !coplanar(vertices, one(vertices[1].x) * 1e-6)
@warn "The polygon is not coplanar with 1e-6 threshold!"
end

Polygon3D(vertices)
end

function isconvex(polygon::Polygon2D)

end

"""
$(TYPEDSIGNATURES)
The internal angles of a convex polygon are all smaller than π,
or equivalently, the cross products of any two adjacent edges have the same direction.
"""
function isconvex(polygon::Polygon3D)
n = length(polygon.vertices)
if n < 4
return true
end

N = normal(polygon)
for i in 1:n
v1 = polygon.vertices[i]
v2 = polygon.vertices[mod1(i+1, n)]
v3 = polygon.vertices[mod1(i+2, n)]
if dot(cross(v2 - v1, v3 - v2), N) < 0
return false
end
end
return true
end

"""
$(TYPEDSIGNATURES)
Compute the unit normal vector from the first three vertices
"""
normal(polygon::Polygon3D) = normal(polygon.vertices[1:3]...)

"""
$(TYPEDSIGNATURES)
First construct a plane from the first three vertices, then iteratively check whether all other vertices are coplanar with this plane or not.
"""
function coplanar(vertices, threshold)
n = length(vertices)

# A concrete polygon have more than 2 vertices
if n == 3
return true
else
plane = Plane(vertices[1:3]...)
for i = 4:n
if !coplanar(vertices[i], plane, threshold)
return false
end
end
return true
end
end

coplanar(polygon::Polygon3D, threshold) = coplanar(polygon.vertices, threshold)

function is_inbound(pos, polygon)

end

### Some common polygons

function polygon_rect()

end

function polygon_regular()

end
33 changes: 30 additions & 3 deletions src/Ray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct Ray3D{T<:Number} <: AbstractRay3D{T}
n::PVector{T}
end

### Ray2D reflect from Line2D

function intersect(ray::Ray2D, line::Line2D)
AB = line.b - line.a
ray_norm = PVector2D(-ray.n.y, ray.n.x) # ⟂ ray
Expand All @@ -39,15 +41,15 @@ function intersect(ray::Ray2D, line::Line2D)
AX = ray.x - line.a
t1 = dot(PVector2D(-AB.y, AB.x), AX) / dot_ray_norm_AB
t2 = dot(AX, ray_norm) / dot_ray_norm_AB
if t1 >= 0 && t2 >= 0 && t2 <= 1
intersection_point = ray.x + ray.n * t1
if t1 >= 0 && t2 >= 0 && t2 <= one(t2)
intersection_point = ray.x + ray.n * t1 # rescaling
return true, intersection_point
else
return false, PVector2D() # no intersection
end
end

reflect(vec::PVector2D, n::PVector2D) = vec - 2*ustrip(n)*dot(vec, ustrip(n))
reflect(vec::AbstractPoint, n::AbstractPoint) = vec - 2*ustrip(n)*dot(vec, ustrip(n))

function reflect(ray::Ray2D, line::Line2D)
hit, intersection = intersect(ray, line)
Expand All @@ -56,4 +58,29 @@ function reflect(ray::Ray2D, line::Line2D)
else
return nothing
end
end

### Ray3D reflect from Plane

function intersect(ray::Ray3D, plane::Plane)
N = normal(plane)
denom = dot(ray.n, N)
if norm(denom) < 1e-6 * unit(denom)
return false, PVector(0, 0, 0) # ∥, no intersection
end
t = dot(plane.a - ray.x, N) / denom
if t < 0
return false, PVector(0, 0, 0) # no intersection
end
intersection_point = ray.x + ray.n * t # rescaling
return true, intersection_point
end

function reflect(ray::Ray3D, plane::Plane)
hit, intersection = intersect(ray, plane)
if hit
return Ray3D(intersection, reflect(ray.n, normal(plane)))
else
return nothing
end
end
42 changes: 40 additions & 2 deletions test/testRay.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@testset "Ray Unitless" begin
@testset "Ray2D Unitless" begin
ray = Ray2D(PVector2D(), PVector2D(1.0, 1.0))
@test ray.theta == π/4

Expand All @@ -16,7 +16,7 @@
@test isnothing(reflect(ray, Line2D(PVector(2, 1), PVector(2, 0))))
end

@testset "Ray Unitful" begin
@testset "Ray2D Unitful" begin
ray = Ray2D(PVector2D(u"m"), PVector2D(1.0u"m", 1.0u"m"))
@test ray.theta == π/4

Expand All @@ -32,4 +32,42 @@ end
@test ray_reflect.theta == 3/4 * π

@test isnothing(reflect(ray, Line2D(PVector(2u"m", 1u"m"), PVector(2u"m", 0u"m"))))
end

@testset "Ray3D Unitless" begin
ray = Ray3D(PVector(), PVector(0.0, 1.0, 1.0))
plane = Plane(PVector(1, 1, 1), PVector(1, 1, -1), PVector(-1, 1, 1))
@test normal(plane) == PVector(0.0, 1.0, 0.0)
hit, intersection_point = intersect(ray, plane)
@test intersection_point == PVector(0.0, 1.0, 1.0)
ray_reflect = reflect(ray, plane)
@test ray_reflect.n == PVector(0.0, -1.0, 1.0)

#: zero incident angle
ray = Ray3D(PVector(), PVector(0.0, 1.0, 0.0))
plane = Plane(PVector(1, 1, 1), PVector(1, 1, -1), PVector(-1, 1, 1))
@test normal(plane) == PVector(0.0, 1.0, 0.0)
hit, intersection_point = intersect(ray, plane)
@test intersection_point == PVector(0.0, 1.0, 0.0)
ray_reflect = reflect(ray, plane)
@test ray_reflect.n == PVector(0.0, -1.0, 0.0)
end

@testset "Ray3D Unitful" begin
ray = Ray3D(PVector(u"m"), PVector(0.0, 1.0, 1.0, u"m"))
plane = Plane(PVector(1, 1, 1, u"m"), PVector(1, 1, -1, u"m"), PVector(-1, 1, 1, u"m"))
@test normal(plane) == PVector(0.0, 1.0, 0.0, u"m")
hit, intersection_point = intersect(ray, plane)
@test intersection_point == PVector(0.0, 1.0, 1.0, u"m")
ray_reflect = reflect(ray, plane)
@test ray_reflect.n == PVector(0.0, -1.0, 1.0, u"m")

#: zero incident angle
ray = Ray3D(PVector(u"m"), PVector(0.0, 1.0, 0.0, u"m"))
plane = Plane(PVector(1, 1, 1, u"m"), PVector(1, 1, -1, u"m"), PVector(-1, 1, 1, u"m"))
@test normal(plane) == PVector(0.0, 1.0, 0.0, u"m")
hit, intersection_point = intersect(ray, plane)
@test intersection_point == PVector(0.0, 1.0, 0.0, u"m")
ray_reflect = reflect(ray, plane)
@test ray_reflect.n == PVector(0.0, -1.0, 0.0, u"m")
end

0 comments on commit 75b1175

Please sign in to comment.