Talk:Ray-casting algorithm: Difference between revisions
Content added Content deleted
(→"Coherent results": sign) |
(→Elixir: new section) |
||
Line 176: | Line 176: | ||
</lang> |
</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> |