-
Notifications
You must be signed in to change notification settings - Fork 40
Added a new "Surface" type: ConvexPolygon which support planner simple convex polygons #213
Changes from 1 commit
f73294e
8ea6bd2
2e04866
12dd2a7
d9ded68
4fef38f
f3597b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# MIT license | ||
# Copyright (c) Microsoft Corporation. All rights reserved. | ||
# See LICENSE in the project root for full license information. | ||
|
||
import Statistics | ||
import GeometricalPredicates | ||
|
||
""" | ||
ConvexPolygon{T} <: Surface{T} | ||
|
||
General Convex Polygon surface, not a valid CSG object. | ||
The rotation of the polygon around its normal is defined by `rotationvec`. | ||
`rotationvec×surfacenormal` is taken as the vector along the u axis. | ||
|
||
```julia | ||
ConvexPolygon(local_frame::Transform{T}, local_polygon_points::Vector{Vector{T}}, interface::NullOrFresnel{T} = nullinterface(T)) | ||
``` | ||
|
||
The local frame defines the plane (spans by the right and up vectors) with the plane normal given by the forward vector. | ||
the local_polygon_points are given with respect to the local frame and are 2D points. | ||
""" | ||
struct ConvexPolygon{T} <: Surface{T} | ||
plane::Plane{T,3} | ||
local_frame::Transform{T} | ||
local_points::Vector{Vector{T}} | ||
|
||
# for efficency | ||
_poly2d::GeometricalPredicates.Polygon2D{GeometricalPredicates.Point2D} | ||
|
||
function ConvexPolygon( | ||
local_frame::Transform{T}, | ||
local_polygon_points::Vector{Vector{T}}, | ||
interface::NullOrFresnel{T} = NullInterface(T) | ||
) where {T<:Real} | ||
|
||
@assert length(local_polygon_points) > 3 # need at least 3 points to define apolygon | ||
@assert size(local_polygon_points[1])[1] == 2 # check that first point is a 2D point | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you use SVector instead of Vector then you can specify vector size variable declaration and can eliminate this assert. |
||
|
||
local_center = Statistics.mean(local_polygon_points) | ||
world_center = local2world(local_frame) * Vec3(local_center[1], local_center[2], zero(T)) | ||
|
||
poly_points = [GeometricalPredicates.Point2D(p[1], p[2]) for p in local_polygon_points] | ||
poly = GeometricalPredicates.Polygon2D(poly_points...) | ||
|
||
plane = Plane(forward(local_frame), world_center, interface = interface) | ||
new{T}(plane, local_frame, local_polygon_points, poly) | ||
end | ||
end | ||
export ConvexPolygon | ||
|
||
# Base.show(io::IO, poly::ConvexPolygon{T}) where {T<:Real} = print(io, "ConvexPolygon{$T}($(centroid(hex)), $(normal(hex)), $(hex.side_length), $(interface(hex)))") | ||
centroid(poly::ConvexPolygon{T}) where {T<:Real} = poly.plane.pointonplane | ||
interface(poly::ConvexPolygon{T}) where {T<:Real} = interface(poly.plane) | ||
normal(poly::ConvexPolygon{T}) where {T<:Real} = normal(poly.plane) | ||
normal(poly::ConvexPolygon{T}, ::T, ::T) where {T<:Real} = normal(poly) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is this function for? If you really need two then the reason should probably be in a documentation string for the normal function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I copied it from the Hexagon example. I think that its just a matter of interface support. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that all the shapes have the same interface - i think that normal without parameters is the one that should be removed but on the other hand what point would you give to a shape that doesn't have a natural parametrization. |
||
|
||
|
||
function surfaceintersection(poly::ConvexPolygon{T}, r::AbstractRay{T,3}) where {T<:Real} | ||
interval = surfaceintersection(poly.plane, r) | ||
if interval isa EmptyInterval{T} || isinfiniteinterval(interval) | ||
return EmptyInterval(T) # no ray plane intersection or inside plane but no hit | ||
else | ||
intersect = halfspaceintersection(interval) | ||
p = point(intersect) | ||
|
||
local_p = world2local(poly.local_frame) * p | ||
@assert abs(local_p[3]) < 0.00001 # need to find a general epsilon - check that the point lies on the plain | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure this assert is necessary. If we have a ray/plane intersection then local_p should always be a valid point. An absolute test is subject to problems with scale, if the convex polygons become large for some reason. Could lead to erroneous failures. |
||
in_poly = GeometricalPredicates.inpolygon(poly._poly2d, GeometricalPredicates.Point(local_p[1], local_p[2])) | ||
|
||
if !in_poly | ||
return EmptyInterval(T) | ||
else | ||
if dot(normal(poly), direction(r)) < zero(T) | ||
return positivehalfspace(intersect) | ||
else | ||
return rayorigininterval(intersect) | ||
end | ||
end | ||
end | ||
end | ||
|
||
|
||
function makemesh(poly::ConvexPolygon{T}, ::Int = 0) where {T<:Real} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is makemesh used for drawing the convex poly in 3D? Maybe a documentation string as to the purpose of this function. |
||
c = centroid(poly) | ||
|
||
l2w = local2world(poly.local_frame) | ||
l = length(poly.local_points) | ||
|
||
triangles = [] | ||
for i in 1:l | ||
p1 = poly.local_points[i] | ||
p2 = poly.local_points[mod(i,l) + 1] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might want to use a variable name other than l here since it looks almost exactly the same as 1 in the code font. Maybe len instead of l? |
||
|
||
tri = Triangle( | ||
Vector(l2w * Vec3(p2[1], p2[2], zero(T))), | ||
Vector(c), | ||
Vector(l2w * Vec3(p1[1], p1[2], zero(T)))) | ||
push!(triangles, tri) | ||
end | ||
|
||
triangles = Vector{Triangle{T}}(triangles) | ||
|
||
return TriangleMesh(triangles) | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
# ----------------------------------------------------------------------------------------------- | ||
# GEOMETRY | ||
# ----------------------------------------------------------------------------------------------- | ||
using ...OpticSim | ||
using StaticArrays | ||
using LinearAlgebra | ||
|
||
|
@@ -233,6 +234,15 @@ function Transform(rotation::AbstractArray{T,2}, translation::AbstractArray{T,1} | |
translation[1], translation[2], translation[3], one(T)) | ||
end | ||
|
||
|
||
# define some utility functions | ||
right(t::Transform{<:Real}) = normalize(Vec3(t[1,1], t[2,1], t[3,1])) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. documentation strings would be helpful here to explain what these functions do and what they are used for. Graphics people will know but optics people might not. |
||
up(t::Transform{<:Real}) = normalize(Vec3(t[1,2], t[2,2], t[3,2])) | ||
forward(t::Transform{<:Real}) = normalize(Vec3(t[1,3], t[2,3], t[3,3])) | ||
OpticSim.origin(t::Transform{<:Real}) = Vec3(t[1,4], t[2,4], t[3,4]) | ||
export right, up, forward, origin | ||
|
||
|
||
""" | ||
rotationX(angle::T) where {T<:Real} -> Transform | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,3 +71,7 @@ end | |
return acos(x) | ||
end | ||
end | ||
|
||
|
||
# some place holders for package level function names | ||
function origin end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. documentation string would be useful otherwise few people will understand what this function definition is for. Maybe show an example of overloading this function? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
local_points should probably be SVector{SVector}. Vectors will be allocated on the heap which will lead to allocations and will probably also be slower. If we expected large convex polygons then Vector might be appropriate. But this class is going to be used for polygons with less than 20-30 points. If you change to SVector probably should document that should only have small number of points.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I replaced it with Vector{SVector{2, T}}.
I can't find a convenient way to define an static array of static arrays. Please send me an example if you have one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you'd have to do something like this:
struct ConvexPolygon{N,T<:Real} <: Surface{T}
local_points::SVector{N,SVector{2,T}}
or maybe even better
struct ConvexPolygon{Npoints,Dim,T<:Real} <: Surface{T}
local_points::SVector{Npoints,SVector{Dim,T}}
where Dim is the dimension of the points, and Npoints is the number of points.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rgal does my suggestion for defined SVector{SVector} work for this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm getting the following error when trying it:
ERROR: LoadError: TypeError: in ConvexPolygon, in N, expected N<:Int64, got a value of type Int64.
this is my entire test:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't want this:
you want this:
The first statement is saying you want N to be a subtype of Int64, which is the same as saying a type equal to Int64 because there are no subtypes of Int64. But the argument you will use in the constructor is a number, not a type.
you'll want to get rid of the N<:Int64 in the ConvexPolygonn constructor as well. I made those two changes and the code worked. This should do it: