diff --git a/include/igl/predicates/ear_clipping.cpp b/include/igl/predicates/ear_clipping.cpp new file mode 100644 index 000000000..ef8ed883d --- /dev/null +++ b/include/igl/predicates/ear_clipping.cpp @@ -0,0 +1,113 @@ + +#include +#include "ear_clipping.h" +#include "point_inside_polygon.h" +#include "predicates.h" + +template +IGL_INLINE bool igl::predicates::is_ear( + const Eigen::MatrixBase& P, + const Eigen::VectorXi& RT, + const Eigen::VectorXi& L, + const Eigen::VectorXi& R, + const int i +){ + typedef typename DerivedP::Scalar Scalar; + + int a = L(i), b = R(i); + if(RT(i) != 0 || RT(a) != 0 || RT(b) != 0) return false; + Eigen::RowVector2d pa = P.row(a); + Eigen::RowVector2d pb = P.row(b); + Eigen::RowVector2d pi = P.row(i); + auto r = igl::predicates::orient2d(pa,pi,pb); + if(r == igl::predicates::Orientation::NEGATIVE || + r == igl::predicates::Orientation::COLLINEAR) return false; + + // check if any vertex is lying inside triangle (a,b,i); + int k=R(b); + while(k!=a){ + Eigen::MatrixX2d T(3,2); + T< +IGL_INLINE void igl::predicates::ear_clipping( + const Eigen::MatrixBase& P, + const Eigen::VectorXi& RT, + Eigen::VectorXi& I, + Eigen::MatrixXi& eF, + Eigen::PlainObjectBase& nP +){ + + Eigen::VectorXi L(P.rows()); + Eigen::VectorXi R(P.rows()); + for(int i=0;i >(Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix&, Eigen::Matrix&, Eigen::PlainObjectBase >&); +#endif \ No newline at end of file diff --git a/include/igl/predicates/ear_clipping.h b/include/igl/predicates/ear_clipping.h new file mode 100644 index 000000000..6588667b4 --- /dev/null +++ b/include/igl/predicates/ear_clipping.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EAR_CLIPPING +#define EAR_CLIPPING + +#include +#include "../igl_inline.h" + +namespace igl +{ + namespace predicates + { + template + IGL_INLINE void ear_clipping( + const Eigen::MatrixBase& P, + const Eigen::VectorXi& RT, + Eigen::VectorXi& I, + Eigen::MatrixXi& eF, + Eigen::PlainObjectBase& nP + ); + + template + IGL_INLINE bool is_ear( + const Eigen::MatrixBase& P, + const Eigen::VectorXi& RT, + const Eigen::VectorXi& L, + const Eigen::VectorXi& R, + const int i + ); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "ear_clipping.cpp" +#endif + + +#endif \ No newline at end of file diff --git a/include/igl/predicates/point_inside_polygon.cpp b/include/igl/predicates/point_inside_polygon.cpp new file mode 100644 index 000000000..0bb1b1909 --- /dev/null +++ b/include/igl/predicates/point_inside_polygon.cpp @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "point_inside_polygon.h" + +template +bool igl::predicates::point_inside_polygon( + const Eigen::Matrix& P, + const Eigen::Matrix& q +){ + for(int i=0;i(Eigen::Matrix const&, Eigen::Matrix const&); +#endif \ No newline at end of file diff --git a/include/igl/predicates/point_inside_polygon.h b/include/igl/predicates/point_inside_polygon.h new file mode 100644 index 000000000..2cd7dc829 --- /dev/null +++ b/include/igl/predicates/point_inside_polygon.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef PREDICATE_POINT_INSIDE_POLYGON_H +#define PREDICATE_POINT_INSIDE_POLYGON_H + + + +#include "../igl_inline.h" +#include +#include "predicates.h" + +namespace igl +{ + namespace predicates + { + // check whether 2d point lies inside 2d polygon + // Inputs: + // P: n*2 polygon, n >= 3 + // q: 2d query point + // Returns true if point is inside polygon + template + bool point_inside_polygon( + const Eigen::Matrix& P, + const Eigen::Matrix& q + ); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "point_inside_polygon.cpp" +#endif + +#endif \ No newline at end of file diff --git a/include/igl/predicates/segment_segment_intersect.cpp b/include/igl/predicates/segment_segment_intersect.cpp new file mode 100644 index 000000000..b79cf7ae2 --- /dev/null +++ b/include/igl/predicates/segment_segment_intersect.cpp @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "segment_segment_intersect.h" + +// https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ +template +IGL_INLINE bool igl::predicates::segment_segment_intersect( + const Eigen::MatrixBase& a, + const Eigen::MatrixBase& b, + const Eigen::MatrixBase& c, + const Eigen::MatrixBase& d +) +{ + typename DerivedP::Scalar Scalar; + + auto t1 = igl::predicates::orient2d(a,b,c); + auto t2 = igl::predicates::orient2d(b,c,d); + auto t3 = igl::predicates::orient2d(a,b,d); + auto t4 = igl::predicates::orient2d(a,c,d); + + // assume m,n,p are colinear, check whether p is in range [m,n] + auto on_segment = []( + const Eigen::MatrixBase& m, + const Eigen::MatrixBase& n, + const Eigen::MatrixBase& p + ){ + return ((p(0) >= std::min(m(0),n(0))) && + (p(0) <= std::max(m(0),n(0))) && + (p(1) >= std::min(m(1),n(1))) && + (p(1) <= std::max(m(1),n(1)))); + }; + + // colinear case + if((t1 == igl::predicates::Orientation::COLLINEAR && on_segment(a,b,c)) || + (t2 == igl::predicates::Orientation::COLLINEAR && on_segment(c,d,b)) || + (t3 == igl::predicates::Orientation::COLLINEAR && on_segment(a,b,d)) || + (t4 == igl::predicates::Orientation::COLLINEAR && on_segment(c,d,a))) + return true; + + // ordinary case + return (t1 != t3 && t2 != t4); +} + +#ifdef IGL_STATIC_LIBRARY +template bool igl::predicates::segment_segment_intersect >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif \ No newline at end of file diff --git a/include/igl/predicates/segment_segment_intersect.h b/include/igl/predicates/segment_segment_intersect.h new file mode 100644 index 000000000..825bc99f7 --- /dev/null +++ b/include/igl/predicates/segment_segment_intersect.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_PREDICATES_SEGMENT_SEGMENT_INTERSECT_H +#define IGL_PREDICATES_SEGMENT_SEGMENT_INTERSECT_H + +#include +#include +#include +namespace igl +{ +namespace predicates +{ + + // Given two segments in 2d test whether they intersect each other + // using orient2D + // + // Inputs: + // A: 1st endpoint of segment 1 + // B: 2st endpoint of segment 1 + // C: 1st endpoint of segment 2 + // D: 2st endpoint of segment 2 + // eps: precision used for colinear case + // Returns true if they intersect + + template + IGL_INLINE bool segment_segment_intersect( + // input: + const Eigen::MatrixBase& A, + const Eigen::MatrixBase& B, + const Eigen::MatrixBase& C, + const Eigen::MatrixBase& D + ); + +} + +} +#ifndef IGL_STATIC_LIBRARY +# include "segment_segment_intersect.cpp" +#endif +#endif //IGL_PREDICATES_SEGMENT_SEGMENT_INTERSECT_H diff --git a/tests/include/igl/predicates/ear_clipping.cpp b/tests/include/igl/predicates/ear_clipping.cpp new file mode 100644 index 000000000..4c7ef95d6 --- /dev/null +++ b/tests/include/igl/predicates/ear_clipping.cpp @@ -0,0 +1,16 @@ +#include +#include + +TEST_CASE("ear_clipping: boolean", "[igl/predicates]") +{ + // Example1: simple polygon + Eigen::MatrixXd polygon(10,2); + polygon<<2,-3,4,1,5.5,-2,6,2.5,5,1,4,5,3,0,1,1,1,5,0,0; + Eigen::VectorXi RT,nR,M; + Eigen::MatrixXi eF; + Eigen::MatrixXd nP; + RT.setZero(polygon.rows()); + igl::predicates::ear_clipping(polygon,RT,M,eF,nP); + REQUIRE(nP.rows() == 0); + +} diff --git a/tests/include/igl/predicates/segment_segment_intersect.cpp b/tests/include/igl/predicates/segment_segment_intersect.cpp new file mode 100644 index 000000000..14f1bb833 --- /dev/null +++ b/tests/include/igl/predicates/segment_segment_intersect.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +TEST_CASE("segment_segment_intersect: robust", "[igl/predicates]") +{ + // example 1: vanila intersecting case + auto A1 = Eigen::RowVector2d(0, 128.5); + auto B1 = Eigen::RowVector2d(-77.44,1.2); + auto C1 = Eigen::RowVector2d(-83.2,2.8); + auto D1 = Eigen::RowVector2d(-1.0,-1.0); + + bool check1 = igl::predicates::segment_segment_intersect(A1,B1,C1,D1); + REQUIRE(check1 == true); + + // example 2: colinear overlapping + auto A2 = Eigen::RowVector2d(1.0,5.0); + auto B2 = Eigen::RowVector2d(1.0,9.0); + auto C2 = Eigen::RowVector2d(1.0,8.0); + auto D2 = Eigen::RowVector2d(1.0,12.0); + + bool check2 = igl::predicates::segment_segment_intersect(A2,B2,C2,D2); + REQUIRE(check2 == true); + + // example 3: colinear touching endpoint + auto A3 = Eigen::RowVector2d(0.0,0.0); + auto B3 = Eigen::RowVector2d(1.5,1.5); + auto C3 = Eigen::RowVector2d(1.5,1.5); + auto D3 = Eigen::RowVector2d(2.0,2.0); + + bool check3 = igl::predicates::segment_segment_intersect(A3,B3,C3,D3); + REQUIRE(check3 == true); + + // example 6: colinear not touching endpoint + double eps = 1e-14; + auto A4 = Eigen::RowVector2d(0.0,0.0); + auto B4 = Eigen::RowVector2d(1.5,1.5); + auto C4 = Eigen::RowVector2d(1.5+eps,1.5+eps); + auto D4 = Eigen::RowVector2d(2.0,2.0); + bool check4 = igl::predicates::segment_segment_intersect(A4,B4,C4,D4); + REQUIRE(check4 == false); + +} \ No newline at end of file