Skip to content

Commit 1caea3b

Browse files
committed
[+] orietation predicate
1 parent f6e97ed commit 1caea3b

File tree

8 files changed

+225
-3
lines changed

8 files changed

+225
-3
lines changed

CMake/Modules/FindGMP.cmake

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# - Try to find the GMP library
2+
# Once done this will define
3+
#
4+
# GMP_FOUND - system has GMP
5+
# GMP_INCLUDE_DIR - the GMP include directory
6+
# GMP_LIBRARIES - The libraries needed to use GMP
7+
8+
if(GMP_INCLUDE_DIR AND GMP_LIBRARIES)
9+
set(GMP_FOUND TRUE)
10+
else(GMP_INCLUDE_DIR AND GMP_LIBRARIES)
11+
12+
find_path(GMP_INCLUDE_DIR gmp.h
13+
/usr/include
14+
/usr/local/include
15+
)
16+
17+
find_library(GMP_LIBRARIES names gmp
18+
PATHS
19+
/usr/lib
20+
/usr/lib64
21+
/usr/local/lib
22+
/usr/local/lib64
23+
)
24+
25+
if(GMP_INCLUDE_DIR AND GMP_LIBRARIES)
26+
set(GMP_FOUND TRUE)
27+
endif(GMP_INCLUDE_DIR AND GMP_LIBRARIES)
28+
29+
30+
if(GMP_FOUND)
31+
if(NOT GMP_FIND_QUIETLY)
32+
message(STATUS "Found GMP: ${GMP_LIBRARIES}")
33+
endif(NOT GMP_FIND_QUIETLY)
34+
else(GMP_FOUND)
35+
if(GMP_FIND_REQUIRED)
36+
message(FATAL_ERROR "could NOT find gmp")
37+
endif(GMP_FIND_REQUIRED)
38+
endif(GMP_FOUND)
39+
40+
MARK_AS_ADVANCED(GMP_INCLUDE_DIR GMP_LIBRARIES)
41+
42+
endif(GMP_INCLUDE_DIR AND GMP_LIBRARIES)

CMakeLists.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
22

33
project(cg-library)
44

5+
SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMake/Modules)
6+
57
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
68

79
find_package(OpenGL REQUIRED)
10+
find_package(GMP REQUIRED)
811

912
find_package(Qt4 COMPONENTS QtOpenGL QtCore QtGui REQUIRED)
1013
include(${QT_USE_FILE})
1114

1215
find_package(Boost REQUIRED)
1316

14-
include_directories(include ${Boost_INCLUDE_DIR})
17+
include_directories(include ${Boost_INCLUDE_DIR} ${GMP_INCLUDE_DIR})
1518

1619
add_subdirectory(include)
1720
add_subdirectory(src)

include/cg/operations/orientation.h

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#pragma once
2+
3+
#include "cg/primitives/point.h"
4+
#include <boost/numeric/interval.hpp>
5+
#include <gmpxx.h>
6+
7+
#include <boost/optional.hpp>
8+
9+
namespace cg
10+
{
11+
enum orientation_t
12+
{
13+
CG_RIGHT = -1,
14+
CG_COLLINEAR = 0,
15+
CG_LEFT = 1
16+
};
17+
18+
struct orientation_d
19+
{
20+
boost::optional<orientation_t> operator() (point_2 const & a, point_2 const & b, point_2 const & c) const
21+
{
22+
double l = (b.x - a.x) * (c.y - a.y);
23+
double r = (b.y - a.y) * (c.x - a.x);
24+
double res = l - r;
25+
double eps = (fabs(l) + fabs(r)) * 8 * std::numeric_limits<double>::epsilon();
26+
27+
if (res > eps)
28+
return CG_LEFT;
29+
30+
if (res < -eps)
31+
return CG_RIGHT;
32+
33+
return boost::none;
34+
}
35+
};
36+
37+
struct orientation_i
38+
{
39+
boost::optional<orientation_t> operator() (point_2 const & a, point_2 const & b, point_2 const & c) const
40+
{
41+
typedef boost::numeric::interval_lib::unprotect<boost::numeric::interval<double> >::type interval;
42+
43+
boost::numeric::interval<double>::traits_type::rounding _;
44+
interval res = (interval(b.x) - a.x) * (interval(c.y) - a.y)
45+
- (interval(b.y) - a.y) * (interval(c.x) - a.x);
46+
47+
if (res.lower() > 0)
48+
return CG_LEFT;
49+
50+
if (res.upper() < 0)
51+
return CG_RIGHT;
52+
53+
if (res.upper() == res.lower())
54+
return CG_COLLINEAR;
55+
56+
return boost::none;
57+
}
58+
};
59+
60+
struct orientation_r
61+
{
62+
boost::optional<orientation_t> operator() (point_2 const & a, point_2 const & b, point_2 const & c) const
63+
{
64+
mpq_class res = (mpq_class(b.x) - a.x) * (mpq_class(c.y) - a.y)
65+
- (mpq_class(b.y) - a.y) * (mpq_class(c.x) - a.x);
66+
67+
int cres = cmp(res, 0);
68+
69+
if (cres > 0)
70+
return CG_LEFT;
71+
72+
if (cres < 0)
73+
return CG_RIGHT;
74+
75+
return CG_COLLINEAR;
76+
}
77+
};
78+
79+
inline orientation_t orientation(point_2 const & a, point_2 const & b, point_2 const & c)
80+
{
81+
if (boost::optional<orientation_t> v = orientation_d()(a, b, c))
82+
return *v;
83+
84+
if (boost::optional<orientation_t> v = orientation_i()(a, b, c))
85+
return *v;
86+
87+
return *orientation_r()(a, b, c);
88+
}
89+
}

include/cg/primitives/point.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ namespace cg
66
{
77
template <class Scalar> struct point_2t;
88

9-
typedef point_2t<float> point_2f;
10-
typedef point_2t<int> point_2i;
9+
typedef point_2t<double> point_2;
10+
typedef point_2t<float> point_2f;
11+
typedef point_2t<int> point_2i;
1112

1213
template <class Scalar>
1314
struct point_2t

include/cg/primitives/vector.h

+20
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ namespace cg
1313
{
1414
Scalar x, y;
1515

16+
vector_2t<Scalar> & operator *= (Scalar s)
17+
{
18+
x *= s;
19+
y *= s;
20+
21+
return *this;
22+
}
23+
1624
vector_2t(Scalar x, Scalar y)
1725
: x(x)
1826
, y(y)
@@ -33,6 +41,18 @@ namespace cg
3341
return x1 * x2 + y1 * y2;
3442
}
3543

44+
template <class Scalar>
45+
vector_2t<Scalar> operator * (vector_2t<Scalar> v, Scalar s)
46+
{
47+
return v *= s;
48+
}
49+
50+
template <class Scalar>
51+
vector_2t<Scalar> operator * (Scalar s, vector_2t<Scalar> v)
52+
{
53+
return v *= s;
54+
}
55+
3656
template <class Scalar>
3757
vector_2t<Scalar> const operator - (vector_2t<Scalar> const & v) { return vector_2t<Scalar>(-v.x, -v.y); }
3858
}

tests/CMakeLists.txt

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
cmake_minimum_required(VERSION 2.8)
2+
3+
project(cg-test)
4+
5+
find_package(GTest REQUIRED)
6+
include_directories(${GTEST_INCLUDE_DIR})
7+
8+
find_package(GMP REQUIRED)
9+
include_directories(${GMP_INCLUDE_DIR})
10+
11+
find_package(Boost COMPONENTS random REQUIRED)
12+
include_directories(${Boost_INCLUDE_DIRS})
13+
link_directories(${Boost_LIBRARYDIR})
14+
15+
set(SOURCES
16+
orientation.cpp
17+
)
18+
19+
add_executable(cg-test ${SOURCES})
20+
target_link_libraries(cg-test ${GTEST_BOTH_LIBRARIES} ${GMP_LIBRARIES})
21+
22+
file(GLOB_RECURSE HEADERS "*.h")
23+
add_custom_target(cg_test_headers SOURCES ${HEADERS})

tests/orientation.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <cg/operations/orientation.h>
4+
#include "random_utils.h"
5+
6+
TEST(orientation, uniform_line)
7+
{
8+
boost::random::mt19937 gen;
9+
boost::random::uniform_real_distribution<> distr(-(1LL << 53), (1LL << 53));
10+
11+
std::vector<cg::point_2> pts = uniform_points(1000);
12+
for (size_t l = 0, ln = 1; ln < pts.size(); l = ln++)
13+
{
14+
cg::point_2 a = pts[l];
15+
cg::point_2 b = pts[ln];
16+
17+
for (size_t k = 0; k != 1000; ++k)
18+
{
19+
double t = distr(gen);
20+
cg::point_2 c = a + t * (b - a);
21+
22+
EXPECT_EQ(cg::orientation(a, b, c), *cg::orientation_r()(a, b, c));
23+
}
24+
}
25+
}

tests/random_utils.h

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#pragma once
2+
3+
#include <boost/random.hpp>
4+
#include <cg/primitives/point.h>
5+
6+
std::vector<cg::point_2> uniform_points(size_t count)
7+
{
8+
boost::random::mt19937 gen;
9+
boost::random::uniform_real_distribution<> distr;
10+
11+
std::vector<cg::point_2> res(count);
12+
for (size_t l = 0; l != count; ++l)
13+
{
14+
res[l].x = distr(gen);
15+
res[l].y = distr(gen);
16+
}
17+
18+
return res;
19+
}

0 commit comments

Comments
 (0)