Ray-casting algorithm: Difference between revisions

Content added Content deleted
(Added PicoLisp)
(add Ada)
Line 71: Line 71:


(To avoid the "ray on vertex" problem, the point is moved upward of a small quantity ε)
(To avoid the "ray on vertex" problem, the point is moved upward of a small quantity ε)

=={{header|Ada}}==

polygons.ads:
<lang Ada>package Polygons is

type Point is record
X, Y : Float;
end record;
type Point_List is array (Positive range <>) of Point;
subtype Segment is Point_List (1 .. 2);
type Polygon is array (Positive range <>) of Segment;

function Create_Polygon (List : Point_List) return Polygon;

function Is_Inside (Who : Point; Where : Polygon) return Boolean;

end Polygons;</lang>

polygons.adb:
<lang Ada>package body Polygons is
EPSILON : constant := 0.00001;

function Ray_Intersects_Segment
(Who : Point;
Where : Segment)
return Boolean
is
The_Point : Point := Who;
Above : Point;
Below : Point;
M_Red : Float;
Red_Is_Infinity : Boolean := False;
M_Blue : Float;
Blue_Is_Infinity : Boolean := False;
begin
if Where (1).Y < Where (2).Y then
Above := Where (2);
Below := Where (1);
else
Above := Where (1);
Below := Where (2);
end if;
if The_Point.Y = Above.Y or The_Point.Y = Below.Y then
The_Point.Y := The_Point.Y + EPSILON;
end if;
if The_Point.Y < Below.Y or The_Point.Y > Above.Y then
return False;
elsif The_Point.X > Above.X and The_Point.X > Below.X then
return False;
elsif The_Point.X < Above.X and The_Point.X < Below.X then
return True;
else
if Above.X /= Below.X then
M_Red := (Above.Y - Below.Y) / (Above.X - Below.X);
else
Red_Is_Infinity := True;
end if;
if Below.X /= The_Point.X then
M_Blue := (The_Point.Y - Below.Y) / (The_Point.X - Below.X);
else
Blue_Is_Infinity := True;
end if;
if Blue_Is_Infinity then
return True;
elsif Red_Is_Infinity then
return False;
elsif M_Blue >= M_Red then
return True;
else
return False;
end if;
end if;
end Ray_Intersects_Segment;

function Create_Polygon (List : Point_List) return Polygon is
Result : Polygon (List'Range);
Side : Segment;
begin
for I in List'Range loop
Side (1) := List (I);
if I = List'Last then
Side (2) := List (List'First);
else
Side (2) := List (I + 1);
end if;
Result (I) := Side;
end loop;
return Result;
end Create_Polygon;

function Is_Inside (Who : Point; Where : Polygon) return Boolean is
Count : Natural := 0;
begin
for Side in Where'Range loop
if Ray_Intersects_Segment (Who, Where (Side)) then
Count := Count + 1;
end if;
end loop;
if Count mod 2 = 0 then
return False;
else
return True;
end if;
end Is_Inside;

end Polygons;</lang>

Example use:

main.adb:
<lang Ada>with Ada.Text_IO;
with Polygons;
procedure Main is
package Float_IO is new Ada.Text_IO.Float_IO (Float);
Test_Points : Polygons.Point_List :=
(( 5.0, 5.0),
( 5.0, 8.0),
(-10.0, 5.0),
( 0.0, 5.0),
( 10.0, 5.0),
( 8.0, 5.0),
( 10.0, 10.0));
Square : Polygons.Polygon :=
((( 0.0, 0.0), (10.0, 0.0)),
((10.0, 0.0), (10.0, 10.0)),
((10.0, 10.0), ( 0.0, 10.0)),
(( 0.0, 10.0), ( 0.0, 0.0)));
Square_Hole : Polygons.Polygon :=
((( 0.0, 0.0), (10.0, 0.0)),
((10.0, 0.0), (10.0, 10.0)),
((10.0, 10.0), ( 0.0, 10.0)),
(( 0.0, 10.0), ( 0.0, 0.0)),
(( 2.5, 2.5), ( 7.5, 2.5)),
(( 7.5, 2.5), ( 7.5, 7.5)),
(( 7.5, 7.5), ( 2.5, 7.5)),
(( 2.5, 7.5), ( 2.5, 2.5)));
Strange : Polygons.Polygon :=
((( 0.0, 0.0), ( 2.5, 2.5)),
(( 2.5, 2.5), ( 0.0, 10.0)),
(( 0.0, 10.0), ( 2.5, 7.5)),
(( 2.5, 7.5), ( 7.5, 7.5)),
(( 7.5, 7.5), (10.0, 10.0)),
((10.0, 10.0), (10.0, 0.0)),
((10.0, 0.0), ( 2.5, 2.5)));
Exagon : Polygons.Polygon :=
((( 3.0, 0.0), ( 7.0, 0.0)),
(( 7.0, 0.0), (10.0, 5.0)),
((10.0, 5.0), ( 7.0, 10.0)),
(( 7.0, 10.0), ( 3.0, 10.0)),
(( 3.0, 10.0), ( 0.0, 5.0)),
(( 0.0, 5.0), ( 3.0, 0.0)));
begin
Ada.Text_IO.Put_Line ("Testing Square:");
for Point in Test_Points'Range loop
Ada.Text_IO.Put ("Point(");
Float_IO.Put (Test_Points (Point).X, 0, 0, 0);
Ada.Text_IO.Put (",");
Float_IO.Put (Test_Points (Point).Y, 0, 0, 0);
Ada.Text_IO.Put
("): " &
Boolean'Image (Polygons.Is_Inside (Test_Points (Point), Square)));
Ada.Text_IO.New_Line;
end loop;
Ada.Text_IO.New_Line;
Ada.Text_IO.Put_Line ("Testing Square_Hole:");
for Point in Test_Points'Range loop
Ada.Text_IO.Put ("Point(");
Float_IO.Put (Test_Points (Point).X, 0, 0, 0);
Ada.Text_IO.Put (",");
Float_IO.Put (Test_Points (Point).Y, 0, 0, 0);
Ada.Text_IO.Put
("): " &
Boolean'Image
(Polygons.Is_Inside (Test_Points (Point), Square_Hole)));
Ada.Text_IO.New_Line;
end loop;
Ada.Text_IO.New_Line;
Ada.Text_IO.Put_Line ("Testing Strange:");
for Point in Test_Points'Range loop
Ada.Text_IO.Put ("Point(");
Float_IO.Put (Test_Points (Point).X, 0, 0, 0);
Ada.Text_IO.Put (",");
Float_IO.Put (Test_Points (Point).Y, 0, 0, 0);
Ada.Text_IO.Put
("): " &
Boolean'Image (Polygons.Is_Inside (Test_Points (Point), Strange)));
Ada.Text_IO.New_Line;
end loop;
Ada.Text_IO.New_Line;
Ada.Text_IO.Put_Line ("Testing Exagon:");
for Point in Test_Points'Range loop
Ada.Text_IO.Put ("Point(");
Float_IO.Put (Test_Points (Point).X, 0, 0, 0);
Ada.Text_IO.Put (",");
Float_IO.Put (Test_Points (Point).Y, 0, 0, 0);
Ada.Text_IO.Put
("): " &
Boolean'Image (Polygons.Is_Inside (Test_Points (Point), Exagon)));
Ada.Text_IO.New_Line;
end loop;
end Main;</lang>

Output:
<pre>Testing Square:
Point(5.0,5.0): TRUE
Point(5.0,8.0): TRUE
Point(-10.0,5.0): FALSE
Point(0.0,5.0): FALSE
Point(10.0,5.0): TRUE
Point(8.0,5.0): TRUE
Point(10.0,10.0): FALSE

Testing Square_Hole:
Point(5.0,5.0): FALSE
Point(5.0,8.0): TRUE
Point(-10.0,5.0): FALSE
Point(0.0,5.0): FALSE
Point(10.0,5.0): TRUE
Point(8.0,5.0): TRUE
Point(10.0,10.0): FALSE

Testing Strange:
Point(5.0,5.0): TRUE
Point(5.0,8.0): FALSE
Point(-10.0,5.0): FALSE
Point(0.0,5.0): FALSE
Point(10.0,5.0): TRUE
Point(8.0,5.0): TRUE
Point(10.0,10.0): FALSE

Testing Exagon:
Point(5.0,5.0): TRUE
Point(5.0,8.0): TRUE
Point(-10.0,5.0): FALSE
Point(0.0,5.0): FALSE
Point(10.0,5.0): TRUE
Point(8.0,5.0): TRUE
Point(10.0,10.0): FALSE</pre>


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==