Talk:Ray-casting algorithm: Difference between revisions

→‎Elixir: new section
(→‎Elixir: new section)
 
Line 176:
 
</lang>
 
== Elixir ==
 
point_in_polygon.ex:
<lang Elixir>defmodule PointInPolygon do
require Integer
 
@doc """
Check if point is inside a polygon
 
## Example
iex> polygon = [[1, 2], [3, 4], [5, 2], [3, 0]]
iex> point = [3, 2]
iex> point_in_polygon?(polygon, point)
true
 
## Example
iex> polygon = [[1, 2], [3, 4], [5, 2], [3, 0]]
iex> point = [1.5, 3]
iex> point_in_polygon?(polygon, point)
false
 
"""
def point_in_polygon?(polygon, point) do
polygon
|> to_segments()
|> Enum.reduce(0, fn segment, count ->
apply(__MODULE__, :ray_intersects_segment, add_epsilon(segment, point)) + count
end)
|> Integer.is_odd()
end
 
def to_segments([p1 | _] = polygon) do
polygon |> Enum.chunk_every(2, 1, [p1]) |> Enum.map(fn segment -> orient_segment(segment) end)
end
 
def orient_segment([a = [_ax, ay], b = [_bx, by]]) when by >= ay do
[a, b]
end
 
def orient_segment([b, a]) do
[a, b]
end
 
def add_epsilon(segment = [[_ax, ay], [_bx, by]], [px, py]) when py == ay or py == by do
[segment, [px, py + 0.00000001]]
end
 
def add_epsilon(segment, point), do: [segment, point]
 
def ray_intersects_segment([[_ax, ay], [_bx, by]], [_px, py]) when py < ay or py > by do
0
end
 
# px >= max(ax, bx)
def ray_intersects_segment([[ax, _ay], [bx, _by]], [px, _py])
when (ax >= bx and px >= ax) or (bx >= ax and px >= bx) do
0
end
 
# px < min(ax, bx)
def ray_intersects_segment([[ax, _ay], [bx, _by]], [px, _py])
when (ax <= bx and px < ax) or (bx <= ax and px < bx) do
1
end
 
def ray_intersects_segment([[ax, ay], [bx, by]], [px, py]) do
m_red = m_red(ax, ay, bx, by)
m_blue = m_blue(ax, ay, px, py)
 
case {m_blue, m_red} do
{:infinity, _} ->
1
 
{_, :infinity} ->
0
 
{m_blue, m_red} when m_blue >= m_red ->
1
 
_ ->
0
end
end
 
def m_red(ax, ay, bx, by) when ax != bx do
(by - ay) / (bx - ax)
end
 
def m_red(_, _, _, _) do
:infinity
end
 
def m_blue(ax, ay, px, py) when ax != px do
(py - ay) / (px - ax)
end
 
def m_blue(_, _, _, _) do
:infinity
end
end</lang>
Anonymous user