2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,4 +1,6 @@
|
|||
{{Wikipedia|Point_in_polygon}}
|
||||
|
||||
<br>
|
||||
Given a point and a polygon, check if the point is inside or outside the polygon using the [[wp:Point in polygon#Ray casting algorithm|ray-casting algorithm]].
|
||||
|
||||
A pseudocode can be simply:
|
||||
|
|
@ -27,6 +29,7 @@ So the problematic points are those inside the white area (the box delimited by
|
|||
|
||||
[[Image:posslope.png|128px|thumb|right]]
|
||||
[[Image:negslope.png|128px|thumb|right]]
|
||||
|
||||
Let us take into account a segment AB (the point A having y coordinate always smaller than B's y coordinate, i.e. point A is always below point B) and a point P. Let us use the cumbersome notation PAX to denote the angle between segment AP and AX, where X is always a point on the horizontal line passing by A with x coordinate bigger than the maximum between the x coordinate of A and the x coordinate of B. As explained graphically by the figures on the right, if PAX is greater than the angle BAX, then the ray starting from P intersects the segment AB. (In the images, the ray starting from P<sub>A</sub> does not intersect the segment, while the ray starting from P<sub>B</sub> in the second picture, intersects the segment).
|
||||
|
||||
Points on the boundary or "on" a vertex are someway special and through this approach we do not obtain ''coherent'' results. They could be treated apart, but it is not necessary to do so.
|
||||
|
|
@ -68,4 +71,5 @@ An algorithm for the previous speech could be (if P is a point, Px is its x coor
|
|||
'''end''' '''if'''
|
||||
'''end''' '''if'''
|
||||
|
||||
(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 <big>ε</big>.)
|
||||
<br><br>
|
||||
|
|
|
|||
81
Task/Ray-casting-algorithm/C++/ray-casting-algorithm.cpp
Normal file
81
Task/Ray-casting-algorithm/C++/ray-casting-algorithm.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const double epsilon = numeric_limits<float>().epsilon();
|
||||
const numeric_limits<double> DOUBLE;
|
||||
const double MIN = DOUBLE.min();
|
||||
const double MAX = DOUBLE.max();
|
||||
|
||||
struct Point { const double x, y; };
|
||||
|
||||
struct Edge {
|
||||
const Point a, b;
|
||||
|
||||
bool operator()(const Point& p) const
|
||||
{
|
||||
if (a.y > b.y) return Edge{ b, a }(p);
|
||||
if (p.y == a.y || p.y == b.y) return operator()({ p.x, p.y + epsilon });
|
||||
if (p.y > b.y || p.y < a.y || p.x > max(a.x, b.x)) return false;
|
||||
if (p.x < min(a.x, b.x)) return true;
|
||||
auto blue = abs(a.x - p.x) > MIN ? (p.y - a.y) / (p.x - a.x) : MAX;
|
||||
auto red = abs(a.x - b.x) > MIN ? (b.y - a.y) / (b.x - a.x) : MAX;
|
||||
return blue >= red;
|
||||
}
|
||||
};
|
||||
|
||||
struct Figure {
|
||||
const string name;
|
||||
const initializer_list<Edge> edges;
|
||||
|
||||
bool contains(const Point& p) const
|
||||
{
|
||||
auto c = 0;
|
||||
for (auto e : edges) if (e(p)) c++;
|
||||
return c % 2 != 0;
|
||||
}
|
||||
|
||||
template<unsigned char W = 3>
|
||||
void check(const initializer_list<Point>& points, ostream& os) const
|
||||
{
|
||||
os << "Is point inside figure " << name << '?' << endl;
|
||||
for (auto p : points)
|
||||
os << " (" << setw(W) << p.x << ',' << setw(W) << p.y << "): " << boolalpha << contains(p) << endl;
|
||||
os << endl;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
const initializer_list<Point> points = { { 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} };
|
||||
const Figure square = { "Square",
|
||||
{ {{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}} }
|
||||
};
|
||||
|
||||
const Figure square_hole = { "Square hole",
|
||||
{ {{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}}
|
||||
}
|
||||
};
|
||||
|
||||
const Figure strange = { "Strange",
|
||||
{ {{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}, {2.5, 2.5}}
|
||||
}
|
||||
};
|
||||
|
||||
const Figure exagon = { "Exagon",
|
||||
{ {{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}}
|
||||
}
|
||||
};
|
||||
|
||||
for(auto f : {square, square_hole, strange, exagon})
|
||||
f.check(points, cout);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"math"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type xy struct {
|
||||
|
|
@ -85,7 +85,12 @@ var tpg = []poly{
|
|||
{p13, p14}, {p14, p9}, {p9, p11}}},
|
||||
}
|
||||
|
||||
var tpt = []xy{{5, 5}, {5, 8}, {-10, 5}, {0, 5}, {10, 5}, {8, 5}, {10, 10}}
|
||||
var tpt = []xy{
|
||||
// test points common in other solutions on this page
|
||||
{5, 5}, {5, 8}, {-10, 5}, {0, 5}, {10, 5}, {8, 5}, {10, 10},
|
||||
// test points that show the problem with "strange"
|
||||
{1, 2}, {2, 1},
|
||||
}
|
||||
|
||||
func main() {
|
||||
for _, pg := range tpg {
|
||||
|
|
|
|||
50
Task/Ray-casting-algorithm/Go/ray-casting-algorithm-3.go
Normal file
50
Task/Ray-casting-algorithm/Go/ray-casting-algorithm-3.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type xy struct {
|
||||
x, y float64
|
||||
}
|
||||
|
||||
type closedPoly struct {
|
||||
name string
|
||||
vert []xy
|
||||
}
|
||||
|
||||
func inside(pt xy, pg closedPoly) bool {
|
||||
if len(pg.vert) < 3 {
|
||||
return false
|
||||
}
|
||||
in := rayIntersectsSegment(pt, pg.vert[len(pg.vert)-1], pg.vert[0])
|
||||
for i := 1; i < len(pg.vert); i++ {
|
||||
if rayIntersectsSegment(pt, pg.vert[i-1], pg.vert[i]) {
|
||||
in = !in
|
||||
}
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
func rayIntersectsSegment(p, a, b xy) bool {
|
||||
return (a.y > p.y) != (b.y > p.y) &&
|
||||
p.x < (b.x-a.x)*(p.y-a.y)/(b.y-a.y)+a.x
|
||||
}
|
||||
|
||||
var tpg = []closedPoly{
|
||||
{"square", []xy{{0, 0}, {10, 0}, {10, 10}, {0, 10}}},
|
||||
{"square hole", []xy{{0, 0}, {10, 0}, {10, 10}, {0, 10}, {0, 0},
|
||||
{2.5, 2.5}, {7.5, 2.5}, {7.5, 7.5}, {2.5, 7.5}, {2.5, 2.5}}},
|
||||
{"strange", []xy{{0, 0}, {2.5, 2.5}, {0, 10}, {2.5, 7.5}, {7.5, 7.5},
|
||||
{10, 10}, {10, 0}, {2.5, 2.5}}},
|
||||
{"exagon", []xy{{3, 0}, {7, 0}, {10, 5}, {7, 10}, {3, 10}, {0, 5}}},
|
||||
}
|
||||
|
||||
var tpt = []xy{{1, 2}, {2, 1}}
|
||||
|
||||
func main() {
|
||||
for _, pg := range tpg {
|
||||
fmt.Printf("%s:\n", pg.name)
|
||||
for _, pt := range tpt {
|
||||
fmt.Println(pt, inside(pt, pg))
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Task/Ray-casting-algorithm/Java/ray-casting-algorithm.java
Normal file
56
Task/Ray-casting-algorithm/Java/ray-casting-algorithm.java
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import static java.lang.Math.*;
|
||||
|
||||
public class RayCasting {
|
||||
|
||||
static boolean intersects(int[] A, int[] B, double[] P) {
|
||||
if (A[1] > B[1])
|
||||
return intersects(B, A, P);
|
||||
|
||||
if (P[1] == A[1] || P[1] == B[1])
|
||||
P[1] += 0.0001;
|
||||
|
||||
if (P[1] > B[1] || P[1] < A[1] || P[0] > max(A[0], B[0]))
|
||||
return false;
|
||||
|
||||
if (P[0] < min(A[0], B[0]))
|
||||
return true;
|
||||
|
||||
double red = (P[1] - A[1]) / (double) (P[0] - A[0]);
|
||||
double blue = (B[1] - A[1]) / (double) (B[0] - A[0]);
|
||||
return red >= blue;
|
||||
}
|
||||
|
||||
static boolean contains(int[][] shape, double[] pnt) {
|
||||
boolean inside = false;
|
||||
int len = shape.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (intersects(shape[i], shape[(i + 1) % len], pnt))
|
||||
inside = !inside;
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
public static void main(String[] a) {
|
||||
double[][] testPoints = {{10, 10}, {10, 16}, {-20, 10}, {0, 10},
|
||||
{20, 10}, {16, 10}, {20, 20}};
|
||||
|
||||
for (int[][] shape : shapes) {
|
||||
for (double[] pnt : testPoints)
|
||||
System.out.printf("%7s ", contains(shape, pnt));
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
final static int[][] square = {{0, 0}, {20, 0}, {20, 20}, {0, 20}};
|
||||
|
||||
final static int[][] squareHole = {{0, 0}, {20, 0}, {20, 20}, {0, 20},
|
||||
{5, 5}, {15, 5}, {15, 15}, {5, 15}};
|
||||
|
||||
final static int[][] strange = {{0, 0}, {5, 5}, {0, 20}, {5, 15}, {15, 15},
|
||||
{20, 20}, {20, 0}};
|
||||
|
||||
final static int[][] hexagon = {{6, 0}, {14, 0}, {20, 10}, {14, 20},
|
||||
{6, 20}, {0, 10}};
|
||||
|
||||
final static int[][][] shapes = {square, squareHole, strange, hexagon};
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package ray_casting
|
||||
|
||||
import java.lang.Double.*
|
||||
import java.lang.Math.*
|
||||
|
||||
data class Point(val x: Double, val y: Double)
|
||||
|
||||
data class Edge(val s: Point, val e: Point) {
|
||||
operator fun invoke(p: Point) : Boolean = when {
|
||||
s.y > e.y -> Edge(e, s).invoke(p)
|
||||
p.y == s.y || p.y == e.y -> invoke(Point(p.x, p.y + epsilon))
|
||||
p.y > e.y || p.y < s.y || p.x > max(s.x, e.x) -> false
|
||||
p.x < min(s.x, e.x) -> true
|
||||
else -> {
|
||||
val blue = if (abs(s.x - p.x) > MIN_VALUE) (p.y - s.y) / (p.x - s.x) else MAX_VALUE
|
||||
val red = if (abs(s.x - e.x) > MIN_VALUE) (e.y - s.y) / (e.x - s.x) else MAX_VALUE
|
||||
blue >= red
|
||||
}
|
||||
}
|
||||
|
||||
val epsilon = 0.00001
|
||||
}
|
||||
|
||||
class Figure(val name: String, val edges: Array<Edge>) {
|
||||
operator fun contains(p: Point) = edges.count({ it(p) }) % 2 != 0
|
||||
}
|
||||
|
||||
object Ray_casting {
|
||||
fun check(figures : Array<Figure>, points : List<Point>) {
|
||||
println("points: " + points)
|
||||
figures.forEach { f ->
|
||||
println("figure: " + f.name)
|
||||
f.edges.forEach { println(" " + it) }
|
||||
println("result: " + (points.map { it in f }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package ray_casting
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val figures = arrayOf(Figure("Square", arrayOf(Edge(Point(0.0, 0.0), Point(10.0, 0.0)), Edge(Point(10.0, 0.0), Point(10.0, 10.0)),
|
||||
Edge(Point(10.0, 10.0), Point(0.0, 10.0)),Edge(Point(0.0, 10.0), Point(0.0, 0.0)))),
|
||||
Figure("Square hole", arrayOf(Edge(Point(0.0, 0.0), Point(10.0, 0.0)), Edge(Point(10.0, 0.0), Point(10.0, 10.0)),
|
||||
Edge(Point(10.0, 10.0), Point(0.0, 10.0)), Edge(Point(0.0, 10.0), Point(0.0, 0.0)), Edge(Point(2.5, 2.5), Point(7.5, 2.5)),
|
||||
Edge(Point(7.5, 2.5), Point(7.5, 7.5)),Edge(Point(7.5, 7.5), Point(2.5, 7.5)), Edge(Point(2.5, 7.5), Point(2.5, 2.5)))),
|
||||
Figure("Strange", arrayOf(Edge(Point(0.0, 0.0), Point(2.5, 2.5)), Edge(Point(2.5, 2.5), Point(0.0, 10.0)),
|
||||
Edge(Point(0.0, 10.0), Point(2.5, 7.5)), Edge(Point(2.5, 7.5), Point(7.5, 7.5)), Edge(Point(7.5, 7.5), Point(10.0, 10.0)),
|
||||
Edge(Point(10.0, 10.0), Point(10.0, 0.0)), Edge(Point(10.0, 0.0), Point(2.5, 2.5)))),
|
||||
Figure("Exagon", arrayOf(Edge(Point(3.0, 0.0), Point(7.0, 0.0)), Edge(Point(7.0, 0.0), Point(10.0, 5.0)), Edge(Point(10.0, 5.0), Point(7.0, 10.0)),
|
||||
Edge(Point(7.0, 10.0), Point(3.0, 10.0)), Edge(Point(3.0, 10.0), Point(0.0, 5.0)), Edge(Point(0.0, 5.0), Point(3.0, 0.0)))))
|
||||
|
||||
val points = listOf(Point(5.0, 5.0), Point(5.0, 8.0), Point(-10.0, 5.0), Point(0.0, 5.0),
|
||||
Point(10.0, 5.0), Point(8.0, 5.0), Point(10.0, 10.0))
|
||||
|
||||
Ray_casting.check(figures, points)
|
||||
}
|
||||
|
|
@ -1,52 +1,51 @@
|
|||
/*REXX pgm checks to see if a horizontal ray from point P intersects a polygon*/
|
||||
call points 5 5, 5 8, -10 5, 0 5, 10 5, 8 5, 10 10
|
||||
A=2.5; B=7.5 /*◄───for shorter args*/
|
||||
call poly 0 0, 10 0, 10 10, 0 10 ; call test 'square'
|
||||
call poly 0 0, 10 0, 10 10, 0 10, A A, B A, B B, A B ; call test 'square hole
|
||||
call poly 0 0, A A, 0 10, A B, B B, 10 10, 10 0 ; call test 'irregular'
|
||||
call poly 3 0, 7 0, 10 5, 7 10, 3 10, 0 5 ; call test 'hexagon'
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
in_out: procedure expose point. poly.; parse arg p; #=0
|
||||
do side=1 to poly.0 by 2; #=#+ray_intersect(p,side)
|
||||
end /*side*/
|
||||
return #//2 /*ODD is inside. EVEN is outside. */
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
points: n=0; v='POINT.'; do j=1 for arg(); n=n+1; _=arg(j); parse var _ xx yy
|
||||
call value v||n'.X',xx
|
||||
call value v||n'.Y',yy
|
||||
end /*j*/
|
||||
call value v'0',n /*define the number of points.*/
|
||||
/*REXX program verifies if a horizontal ray from point P intersects a polygon. */
|
||||
call points 5 5, 5 8, -10 5, 0 5, 10 5, 8 5, 10 10
|
||||
A=2.5; B=7.5 /* ◄───── used for shorter arguments (below).*/
|
||||
call poly 0 0, 10 0, 10 10, 0 10 ; call test 'square'
|
||||
call poly 0 0, 10 0, 10 10, 0 10, A A, B A, B B, A B ; call test 'square hole'
|
||||
call poly 0 0, A A, 0 10, A B, B B, 10 10, 10 0 ; call test 'irregular'
|
||||
call poly 3 0, 7 0, 10 5, 7 10, 3 10, 0 5 ; call test 'hexagon'
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
in$out: procedure expose point. poly.; parse arg p; #=0
|
||||
do side=1 to poly.0 by 2; #=#+intersect(p,side); end /*side*/
|
||||
return # // 2 /*ODD is inside. EVEN is outside.*/
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
intersect: procedure expose point. poly.; parse arg ?,s; sp=s+1
|
||||
epsilon='1e' || (-digits()%2); infinity="1e" || (digits() *2)
|
||||
Px=point.?.x; Ax=poly.s.x; Ay=poly.s.y
|
||||
Py=point.?.y; Bx=poly.sp.x; By=poly.sp.y /* [↓] do a swap.*/
|
||||
if Ay>By then parse value Ax Ay Bx By with Bx By Ax Ay
|
||||
if Py=Ay | Py=By then Py=Py + epsilon
|
||||
if Py<Ay | Py>By | Px>max(Ax,Bx) then return 0
|
||||
if Px<min(Ax,Bx) then return 1
|
||||
if Ax\=Bx then m_red =(By-Ay) / (Bx-Ax)
|
||||
else m_red =infinity
|
||||
if Ax\=Px then m_blue=(Py-Ay) / (Px-Ax)
|
||||
else return 1
|
||||
return m_blue >= m_red
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
points: wx=0; wy=0; do j=1 for arg(); parse value arg(j) with xx yy
|
||||
wx=max(wx, length(xx) ); call value 'POINT.'j".X", xx
|
||||
wy=max(wy, length(yy) ); call value 'POINT.'j".Y", yy
|
||||
end /*j*/
|
||||
call value point.0, j-1 /*define the number of points. */
|
||||
return
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
poly: n=0; v='POLY.'; parse arg Fx Fy /* [↓] process the X,Y points*/
|
||||
|
||||
do j=1 for arg(); n=n+1; _=arg(j); parse var _ xx yy
|
||||
call value v||n'.X', word(_,1); call value v||n'.Y', word(_,2)
|
||||
if n//2 then iterate
|
||||
n=n+1
|
||||
call value v||n'.X', word(_,1); call value v||n'.Y', word(_,2)
|
||||
end /*j*/
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
poly: @='POLY.'; parse arg Fx Fy /* [↓] process the X,Y points.*/
|
||||
n=0
|
||||
do j=1 for arg(); n=n+1; parse value arg(j) with xx yy
|
||||
call value @ || n'.X', xx ; call value @ || n".Y", yy
|
||||
if n//2 then iterate; n=n+1
|
||||
call value @ || n'.X', xx ; call value @ || n".Y", yy
|
||||
end /*j*/
|
||||
n=n+1
|
||||
call value v||n".X", Fx; call value v||n".Y", Fy; call value v'0',n
|
||||
return /*POLY.0 is number of segments/sides.*/
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
ray_intersect: procedure expose point. poly.; parse arg ?,s; sp=s+1
|
||||
epsilon='1e' || (digits()%2); infinity='1e' || (digits() *2)
|
||||
Px=point.?.x; Ax=poly.s.x; Ay=poly.s.y
|
||||
Py=point.?.y; Bx=poly.sp.x; By=poly.sp.y /* [↓] do a swap*/
|
||||
if Ay>By then parse value Ax Ay Bx By with Bx By Ax Ay
|
||||
if Py=Ay | Py=By then Py=Py+epsilon
|
||||
if Py<Ay | Py>By | Px>max(Ax,Bx) then return 0
|
||||
if Px<min(Ax,Bx) then return 1
|
||||
if Ax\=Bx then m_red =(By-Ay)/(Bx-Ax)
|
||||
else m_red =infinity
|
||||
if Ax\=Px then m_blue=(Py-Ay)/(Px-Ax)
|
||||
else return 1
|
||||
return m_blue>=m_red
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
test: say; do k=1 for point.0; say right(' ['arg(1)"] point:",30),
|
||||
right(point.k.x', 'point.k.y, 9) " is ",
|
||||
word('outside inside', in_out(k)+1)
|
||||
end /*k*/
|
||||
return
|
||||
call value @ || n'.X', Fx; call value @ || n".Y", Fy; call value @'0',n
|
||||
return /*POLY.0 is # segments(sides).*/
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
test: say; do k=1 for point.0; w=wx+wy+2
|
||||
say right(' ['arg(1)"] point:", 30),
|
||||
right( right(point.k.x, wx)', 'right(point.k.y, wy), w) " is ",
|
||||
right( word('outside inside', in$out(k)+1), 7)
|
||||
end /*k*/
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,46 +1,47 @@
|
|||
case class Figure(name: String, edges: ((Double, Double), (Double, Double))*) {}
|
||||
package scala.ray_casting
|
||||
|
||||
case class Edge(_1: (Double, Double), _2: (Double, Double)) {
|
||||
import Math._
|
||||
import Double._
|
||||
|
||||
def raySegI(p: (Double, Double)): Boolean = {
|
||||
if (_1._2 > _2._2) return Edge(_2, _1).raySegI(p)
|
||||
if (p._2 == _1._2 || p._2 == _2._2) return raySegI((p._1, p._2 + epsilon))
|
||||
if (p._2 > _2._2 || p._2 < _1._2 || p._1 > max(_1._1, _2._1))
|
||||
return false
|
||||
if (p._1 < min(_1._1, _2._1)) return true
|
||||
val blue = if (abs(_1._1 - p._1) > MinValue) (p._2 - _1._2) / (p._1 - _1._1) else MaxValue
|
||||
val red = if (abs(_1._1 - _2._1) > MinValue) (_2._2 - _1._2) / (_2._1 - _1._1) else MaxValue
|
||||
blue >= red
|
||||
}
|
||||
|
||||
final val epsilon = 0.00001
|
||||
}
|
||||
|
||||
case class Figure(name: String, edges: Seq[Edge]) {
|
||||
def contains(p: (Double, Double)) = edges.count(_.raySegI(p)) % 2 != 0
|
||||
}
|
||||
|
||||
object Ray_casting extends App {
|
||||
import Math._
|
||||
import Double._
|
||||
val figures = Seq(Figure("Square", Seq(((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)))),
|
||||
Figure("Square hole", Seq(((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)))),
|
||||
Figure("Strange", Seq(((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)))),
|
||||
Figure("Exagon", Seq(((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)))))
|
||||
|
||||
val figures = Array(Figure("Square", ((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))),
|
||||
Figure("Square hole", ((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))),
|
||||
Figure("Strange", ((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), (2.5, 2.5))),
|
||||
Figure("Exagon", ((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))))
|
||||
val points = Seq((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))
|
||||
|
||||
val points = Array((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))
|
||||
println("points: " + points)
|
||||
for (f <- figures) {
|
||||
println("figure: " + f.name)
|
||||
println(" " + f.edges)
|
||||
println("result: " + (points map f.contains))
|
||||
}
|
||||
|
||||
figures foreach { f =>
|
||||
println("Is point inside figure " + f.name + '?')
|
||||
points foreach { p => println(" " + p + ": " + contains(f, p)) }
|
||||
println
|
||||
}
|
||||
|
||||
private def raySegI(p: (Double, Double), e: ((Double, Double), (Double, Double))): Boolean = {
|
||||
val epsilon = 0.00001
|
||||
if (e._1._2 > e._2._2)
|
||||
return raySegI(p, (e._2, e._1))
|
||||
if (p._2 == e._1._2 || p._2 == e._2._2)
|
||||
return raySegI((p._1, p._2 + epsilon), e)
|
||||
if (p._2 > e._2._2 || p._2 < e._1._2 || p._1 > max(e._1._1, e._2._1))
|
||||
return false
|
||||
if (p._1 < min(e._1._1, e._2._1))
|
||||
return true
|
||||
val blue = if (abs(e._1._1 - p._1) > MinValue) (p._2 - e._1._2) / (p._1 - e._1._1) else MaxValue
|
||||
val red = if (abs(e._1._1 - e._2._1) > MinValue) (e._2._2 - e._1._2) / (e._2._1 - e._1._1) else MaxValue
|
||||
blue >= red
|
||||
}
|
||||
|
||||
private def contains(f: Figure, p: (Double, Double)) = f.edges.count(raySegI(p, _)) % 2 != 0
|
||||
private implicit def to_edge(p: ((Double, Double), (Double, Double))): Edge = Edge(p._1, p._2)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue