// Copyright (c) 2009 GeometryFactory (France), INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you may redistribute it under // the terms of the Q Public License version 1.0. // See the file LICENSE.QPL distributed with CGAL. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // // // Author(s) : Laurent Rineau, Stephane Tayeb // //****************************************************************************** // File Description : Implements triangle_3 segment_3 intersection construction. // // This implementation is adapted from Triangle_3_Segment_3_do_intersect.h. //****************************************************************************** #ifndef CGAL_TRIANGLE_3_SEGMENT_3_INTERSECTION_H #define CGAL_TRIANGLE_3_SEGMENT_3_INTERSECTION_H #include #include namespace CGAL { namespace internal { template Object t3s3_intersection_coplanar_aux(const typename K::Point_3& a, const typename K::Point_3& b, const typename K::Point_3& c, const typename K::Point_3& p, const typename K::Point_3& q, const bool negative_side, const K& k) { // This function is designed to clip pq into the triangle abc. // Point configuration should be as follows // // +q // | +a // | // +c | +b // | // +p // // We know that c is isolated on the negative side of pq, but we don't know // p position wrt [bc]&[ca] and q position wrt [bc]&[ca] typedef typename K::Point_3 Point_3; typename K::Coplanar_orientation_3 coplanar_orientation = k.coplanar_orientation_3_object(); typename K::Intersect_3 intersection = k.intersect_3_object(); typename K::Construct_line_3 line = k.construct_line_3_object(); typename K::Construct_segment_3 segment = k.construct_segment_3_object(); const Orientation bcq = coplanar_orientation(b,c,q); const Orientation cap = coplanar_orientation(c,a,p); if ( NEGATIVE == bcq || NEGATIVE == cap ) return Object(); else if ( COLLINEAR == bcq ) // q is inside [c,b], p is outside t (because of pqc) return make_object(q); else if ( COLLINEAR == cap ) // p is inside [c,a], q is outside t (because of pqc) return make_object(p); else // bcq == POSITIVE && cap == POSITIVE { // Here we know the intersection is not empty // Let's get the intersection points Point_3 p_side_end_point(p); if ( NEGATIVE == coplanar_orientation(b,c,p) ) { Object obj = intersection(line(p,q),line(b,c)); const Point_3* p_temp = object_cast(&obj); if ( NULL != p_temp ) p_side_end_point = *p_temp; } Point_3 q_side_end_point(q); if ( NEGATIVE == coplanar_orientation(c,a,q) ) { Object obj = intersection(line(p,q),line(c,a)); const Point_3* p_temp = object_cast(&obj); if ( NULL != p_temp ) q_side_end_point = *p_temp; } if ( negative_side ) return make_object(segment(p_side_end_point, q_side_end_point)); else return make_object(segment(q_side_end_point, p_side_end_point)); } } template Object t3s3_intersection_coplanar_aux(const typename K::Point_3& a, const typename K::Point_3& b, const typename K::Point_3& p, const typename K::Point_3& q, const K& k) { // Builds resulting segment of intersection of [a,b] and [p,q] // Precondition: [a,b] and [p,q] have the same direction typename K::Construct_segment_3 segment = k.construct_segment_3_object(); typename K::Collinear_are_ordered_along_line_3 collinear_ordered = k.collinear_are_ordered_along_line_3_object(); // possible orders: [p,a,b,q], [p,a,q,b], [a,p,b,q], [a,p,q,b] if ( collinear_ordered(p,a,q) ) { // p is before a if ( collinear_ordered(p,b,q) ) return make_object(segment(a,b)); else return make_object(segment(a,q)); } else { // p is after a if ( collinear_ordered(p,b,q) ) return make_object(segment(p,b)); else return make_object(segment(p,q)); } } template Object intersection_coplanar(const typename K::Triangle_3 &t, const typename K::Segment_3 &s, const K & k ) { CGAL_kernel_precondition( ! k.is_degenerate_3_object()(t) ) ; CGAL_kernel_precondition( ! k.is_degenerate_3_object()(s) ) ; typedef typename K::Point_3 Point_3; typename K::Construct_point_on_3 point_on = k.construct_point_on_3_object(); typename K::Construct_vertex_3 vertex_on = k.construct_vertex_3_object(); typename K::Coplanar_orientation_3 coplanar_orientation = k.coplanar_orientation_3_object(); typename K::Collinear_are_ordered_along_line_3 collinear_ordered = k.collinear_are_ordered_along_line_3_object(); typename K::Construct_line_3 line = k.construct_line_3_object(); typename K::Construct_segment_3 segment = k.construct_segment_3_object(); const Point_3 & p = point_on(s,0); const Point_3 & q = point_on(s,1); const Point_3 & A = vertex_on(t,0); const Point_3 & B = vertex_on(t,1); const Point_3 & C = vertex_on(t,2); int k0 = 0; int k1 = 1; int k2 = 2; // Determine the orientation of the triangle in the common plane if (coplanar_orientation(A,B,C) != POSITIVE) { // The triangle is not counterclockwise oriented // swap two vertices. std::swap(k1,k2); } const Point_3& a = vertex_on(t,k0); const Point_3& b = vertex_on(t,k1); const Point_3& c = vertex_on(t,k2); // Test whether the segment's supporting line intersects the // triangle in the common plane const Orientation pqa = coplanar_orientation(p,q,a); const Orientation pqb = coplanar_orientation(p,q,b); const Orientation pqc = coplanar_orientation(p,q,c); switch ( pqa ) { // ----------------------------------- // pqa POSITIVE // ----------------------------------- case POSITIVE: switch ( pqb ) { case POSITIVE: switch ( pqc ) { case POSITIVE: // the triangle lies in the positive halfspace // defined by the segment's supporting line. return Object(); case NEGATIVE: // c is isolated on the negative side return t3s3_intersection_coplanar_aux(a,b,c,p,q,true,k); case COLLINEAR: if ( collinear_ordered(p,c,q) ) // c is inside [p,q] return make_object(c); else return Object(); } case NEGATIVE: if ( POSITIVE == pqc ) // b is isolated on the negative side return t3s3_intersection_coplanar_aux(c,a,b,p,q,true,k); else // a is isolated on the positive side return t3s3_intersection_coplanar_aux(b,c,a,q,p,false,k); case COLLINEAR: switch ( pqc ) { case POSITIVE: if ( collinear_ordered(p,b,q) ) // b is inside [p,q] return make_object(b); else return Object(); case NEGATIVE: // a is isolated on the positive side return t3s3_intersection_coplanar_aux(b,c,a,q,p,false,k); case COLLINEAR: // b,c,p,q are aligned, [p,q]&[b,c] have the same direction return t3s3_intersection_coplanar_aux(b,c,p,q,k); } default: // should not happen. CGAL_kernel_assertion(false); return Object(); } // ----------------------------------- // pqa NEGATIVE // ----------------------------------- case NEGATIVE: switch ( pqb ) { case POSITIVE: if ( POSITIVE == pqc ) // a is isolated on the negative side return t3s3_intersection_coplanar_aux(b,c,a,p,q,true,k); else // b is isolated on the positive side return t3s3_intersection_coplanar_aux(c,a,b,q,p,false,k); case NEGATIVE: switch ( pqc ) { case POSITIVE: // c is isolated on the positive side return t3s3_intersection_coplanar_aux(a,b,c,q,p,false,k); case NEGATIVE: // the triangle lies in the negative halfspace // defined by the segment's supporting line. return Object(); case COLLINEAR: if ( collinear_ordered(p,c,q) ) // c is inside [p,q] return make_object(c); else return Object(); } case COLLINEAR: switch ( pqc ) { case POSITIVE: // a is isolated on the negative side return t3s3_intersection_coplanar_aux(b,c,a,p,q,true,k); case NEGATIVE: if ( collinear_ordered(p,b,q) ) // b is inside [p,q] return make_object(b); else return Object(); case COLLINEAR: // b,c,p,q are aligned, [p,q]&[c,b] have the same direction return t3s3_intersection_coplanar_aux(c,b,p,q,k); } default: // should not happen. CGAL_kernel_assertion(false); return Object(); } // ----------------------------------- // pqa COLLINEAR // ----------------------------------- case COLLINEAR: switch ( pqb ) { case POSITIVE: switch ( pqc ) { case POSITIVE: if ( collinear_ordered(p,a,q) ) // a is inside [p,q] return make_object(a); else return Object(); case NEGATIVE: // b is isolated on the positive side return t3s3_intersection_coplanar_aux(c,a,b,q,p,false,k); case COLLINEAR: // a,c,p,q are aligned, [p,q]&[c,a] have the same direction return t3s3_intersection_coplanar_aux(c,a,p,q,k); } case NEGATIVE: switch ( pqc ) { case POSITIVE: // b is isolated on the negative side return t3s3_intersection_coplanar_aux(c,a,b,p,q,true,k); case NEGATIVE: if ( collinear_ordered(p,a,q) ) // a is inside [p,q] return make_object(a); else return Object(); case COLLINEAR: // a,c,p,q are aligned, [p,q]&[a,c] have the same direction return t3s3_intersection_coplanar_aux(a,c,p,q,k); } case COLLINEAR: switch ( pqc ) { case POSITIVE: // a,b,p,q are aligned, [p,q]&[a,b] have the same direction return t3s3_intersection_coplanar_aux(a,b,p,q,k); case NEGATIVE: // a,b,p,q are aligned, [p,q]&[b,a] have the same direction return t3s3_intersection_coplanar_aux(b,a,p,q,k); case COLLINEAR: // case pqc == COLLINEAR is impossible since the triangle is // assumed to be non flat CGAL_kernel_assertion(false); return Object(); } default: // should not happen. CGAL_kernel_assertion(false); return Object(); } default:// should not happen. CGAL_kernel_assertion(false); return Object(); } } template Object intersection(const typename K::Triangle_3 &t, const typename K::Segment_3 &s, const K & k) { CGAL_kernel_precondition( ! k.is_degenerate_3_object()(t) ) ; CGAL_kernel_precondition( ! k.is_degenerate_3_object()(s) ) ; typedef typename K::Point_3 Point_3; typename K::Construct_point_on_3 point_on = k.construct_point_on_3_object(); typename K::Construct_vertex_3 vertex_on = k.construct_vertex_3_object(); typename K::Orientation_3 orientation = k.orientation_3_object(); typename K::Intersect_3 intersection = k.intersect_3_object(); const Point_3 & a = vertex_on(t,0); const Point_3 & b = vertex_on(t,1); const Point_3 & c = vertex_on(t,2); const Point_3 & p = point_on(s,0); const Point_3 & q = point_on(s,1); const Orientation abcp = orientation(a,b,c,p); const Orientation abcq = orientation(a,b,c,q); switch ( abcp ) { case POSITIVE: switch ( abcq ) { case POSITIVE: // the segment lies in the positive open halfspaces defined by the // triangle's supporting plane return Object(); case NEGATIVE: // p sees the triangle in counterclockwise order if ( orientation(p,q,a,b) != POSITIVE && orientation(p,q,b,c) != POSITIVE && orientation(p,q,c,a) != POSITIVE ) return intersection(s,t.supporting_plane()); else return Object(); case COPLANAR: // q belongs to the triangle's supporting plane // p sees the triangle in counterclockwise order if ( orientation(p,q,a,b) != POSITIVE && orientation(p,q,b,c) != POSITIVE && orientation(p,q,c,a) != POSITIVE ) return make_object(q); else return Object(); default: // should not happen. CGAL_kernel_assertion(false); return Object(); } case NEGATIVE: switch ( abcq ) { case POSITIVE: // q sees the triangle in counterclockwise order if ( orientation(q,p,a,b) != POSITIVE && orientation(q,p,b,c) != POSITIVE && orientation(q,p,c,a) != POSITIVE ) return intersection(s,t.supporting_plane()); else return Object(); case NEGATIVE: // the segment lies in the negative open halfspaces defined by the // triangle's supporting plane return Object(); case COPLANAR: // q belongs to the triangle's supporting plane // p sees the triangle in clockwise order if ( orientation(q,p,a,b) != POSITIVE && orientation(q,p,b,c) != POSITIVE && orientation(q,p,c,a) != POSITIVE ) return make_object(q); else return Object(); default: // should not happen. CGAL_kernel_assertion(false); return Object(); } case COPLANAR: // p belongs to the triangle's supporting plane switch ( abcq ) { case POSITIVE: // q sees the triangle in counterclockwise order if ( orientation(q,p,a,b) != POSITIVE && orientation(q,p,b,c) != POSITIVE && orientation(q,p,c,a) != POSITIVE ) return make_object(p); else return Object(); case NEGATIVE: // q sees the triangle in clockwise order if ( orientation(p,q,a,b) != POSITIVE && orientation(p,q,b,c) != POSITIVE && orientation(p,q,c,a) != POSITIVE ) return make_object(p); else return Object(); case COPLANAR: // the segment is coplanar with the triangle's supporting plane // we test whether the segment intersects the triangle in the common // supporting plane return intersection_coplanar(t,s,k); default: // should not happen. CGAL_kernel_assertion(false); return Object(); } default: // should not happen. CGAL_kernel_assertion(false); return Object(); } } template inline Object intersection(const typename K::Segment_3 &s, const typename K::Triangle_3 &t, const K & k) { return internal::intersection(t,s,k); } } // end namespace internal template inline Object intersection(const Triangle_3 &t, const Segment_3 &s) { return typename K::Intersect_3()(t, s); } template inline Object intersection(const Segment_3 &s, const Triangle_3 &t) { return typename K::Intersect_3()(t, s); } } // end namespace CGAL #endif // CGAL_TRIANGLE_3_SEGMENT_3_INTERSECTION_H