//! Generate a new item to visit based on the adjacent triangle at index next. boost::optional<edge_item> prepare_adjacent_traversal( std::size_t next, const edge_item& item ) { comparison_policy cmp( 0 ); bool allAround = get<0>( item.lo ) == constants::infinity<coordinate_type>() && get<0>( item.hi ) == constants::negative_infinity<coordinate_type>(); const std::size_t* fromIndices = m_mesh.get_triangle_indices( item.to ); const std::size_t* toIndices = m_mesh.get_triangle_indices( next ); std::size_t side = get_triangle_adjacent_side( fromIndices, toIndices ); auto pointLo = m_mesh.get_triangle_vertices( item.to )[side]; auto pointHi = m_mesh.get_triangle_vertices( item.to )[(side + 1) % 3]; if( exterior_product_area( pointHi - pointLo, m_origin - pointLo ) < constants::zero<decltype(std::declval<coordinate_type>() * std::declval<coordinate_type>())>() ) std::swap( pointLo, pointHi ); if (!is_segment_in_range_2d(make_segment(pointLo, pointHi), item.lo, item.hi, m_origin)) return boost::none; #if GEOMETRIX_TEST_ENABLED(GEOMETRIX_DEBUG_VISIBLE_VERTICES_MESH_SEARCH) //polygon2 pTri(mMesh.get_triangle_vertices(item.from), mMesh.get_triangle_vertices(item.from) + 3); typedef std::vector<point_t> polygon2; typedef segment<point_t> segment2; polygon2 cTri(m_mesh.get_triangle_vertices(item.to), m_mesh.get_triangle_vertices(item.to) + 3); polygon2 nTri(m_mesh.get_triangle_vertices(next), m_mesh.get_triangle_vertices(next) + 3); segment2 sLo{ m_origin, m_origin + item.lo }; segment2 sHi{ m_origin, m_origin + item.hi }; segment2 cLo{ m_origin, pointLo }; segment2 cHi{ m_origin, pointHi }; #endif vector_t vecLo, vecHi; if( !numeric_sequence_equals_2d(m_origin, pointLo, cmp) && !numeric_sequence_equals_2d(m_origin, pointHi, cmp) ) { assign( vecLo, pointLo - m_origin ); assign( vecHi, pointHi - m_origin ); if (!allAround) { vecLo = is_vector_between(item.lo, item.hi, vecLo, false, cmp) ? vecLo : item.lo; vecHi = is_vector_between(item.lo, item.hi, vecHi, false, cmp) ? vecHi : item.hi; } if (get_orientation(vecHi, vecLo, cmp) == geometrix::oriented_left) return boost::none; } else { assign( vecLo, constants::infinity<coordinate_type>(), constants::zero<coordinate_type>() ); assign( vecHi, constants::negative_infinity<coordinate_type>(), constants::zero<coordinate_type>() ); } #if GEOMETRIX_TEST_ENABLED(GEOMETRIX_DEBUG_VISIBLE_VERTICES_MESH_SEARCH) segment2 nLo{ m_origin, m_origin + vecLo }; segment2 nHi{ m_origin, m_origin + vecHi }; #endif return edge_item( item.to, next, vecLo, vecHi ); }
//! Visit the item and return true/false if the search should continue. bool visit( const edge_item& item ) { bool allAround = get<0>( item.lo ) == constants::infinity<coordinate_type>() && get<0>( item.hi ) == constants::negative_infinity<coordinate_type>(); const std::size_t* toIndices = m_mesh.get_triangle_indices( item.to ); if( allAround ) { m_vertices.push_back( toIndices[0] ); m_vertices.push_back( toIndices[1] ); m_vertices.push_back( toIndices[2] ); } else { const std::size_t* fromIndices = m_mesh.get_triangle_indices( item.from ); comparison_policy cmp( 0 ); for( std::size_t i = 0; i < 3; ++i ) { if( fromIndices[0] == toIndices[i] || fromIndices[1] == toIndices[i] || fromIndices[2] == toIndices[i] ) continue; const auto& point = m_mesh.get_triangle_vertices( item.to )[i]; vector_t vPoint = point - m_origin; if( is_vector_between( item.lo, item.hi, vPoint, true, cmp ) ) m_vertices.push_back( toIndices[i] ); } } return true; }
inline orientation_type point_polyline_orientation(const Point& p, const Polyline& pline, const NumberComparisonPolicy& cmp) { BOOST_CONCEPT_ASSERT((PointSequenceConcept<Polyline>)); BOOST_CONCEPT_ASSERT((NumberComparisonPolicyConcept<NumberComparisonPolicy>)); using access = point_sequence_traits<Polyline>; GEOMETRIX_ASSERT(access::size(pline) > 1); using length_t = typename select_arithmetic_type_from_sequences<Point, typename access::point_type>::type; using area_t = decltype(std::declval<length_t>() * std::declval<length_t>()); using dimensionless_t = decltype(std::declval<length_t>() / std::declval<length_t>()); using vector_t = vector<length_t, dimension_of<Point>::value>; auto minDistance = (std::numeric_limits<area_t>::max)(); std::size_t segIndex; for (std::size_t i = 0, j = 1; j < access::size(pline); i = j++) { auto d2 = point_segment_distance_sqrd(p, access::get_point(pline, i), access::get_point(pline, j)); if (d2 < minDistance) { minDistance = d2; segIndex = i; } } if (cmp.greater_than(minDistance, constants::zero<area_t>())) { GEOMETRIX_ASSERT(minDistance < (std::numeric_limits<area_t>::max)()); auto pi = access::get_point(pline, segIndex); auto pj = access::get_point(pline, segIndex + 1); dimensionless_t t; point_segment_closest_point_and_param(p, pi, pj, t); if (t > constants::zero<dimensionless_t>() && t < constants::one<dimensionless_t>()) return get_orientation(pi, pj, p, cmp); else if (cmp.equals(t, constants::zero<dimensionless_t>())) { //! Closest point is a vertex i. if (segIndex != 0) { auto ph = access::get_point(pline, segIndex - 1); auto o = get_orientation(ph, pi, pj, cmp); if (o == oriented_left) { vector_t vpi = p - pi; vector_t lo = pj - pi; vector_t hi = ph - pi; if (is_vector_between(lo, hi, vpi, false, cmp)) return oriented_left; else return oriented_right; } else if (o == oriented_right) { vector_t vpi = p - pi; vector_t hi = pj - pi; vector_t lo = ph - pi; if (is_vector_between(lo, hi, vpi, false, cmp)) return oriented_right; else return oriented_left; } else return get_orientation(pi, pj, p, cmp); } else return get_orientation(pi, pj, p, cmp); } else { //! pj is the closest. if ((segIndex + 2) < access::size(pline)) { auto pk = access::get_point(pline, segIndex + 2); auto o = get_orientation(pi, pj, pk, cmp); if (o == oriented_left) { vector_t vpj = p - pj; vector_t lo = pk - pj; vector_t hi = pi - pj; if (is_vector_between(lo, hi, vpj, false, cmp)) return oriented_left; else return oriented_right; } else if (o == oriented_right) { vector_t vpj = p - pj; vector_t hi = pk - pj; vector_t lo = pi - pj; if (is_vector_between(lo, hi, vpj, false, cmp)) return oriented_right; else return oriented_left; } else return get_orientation(pi, pj, p, cmp); } else return get_orientation(pi, pj, p, cmp); } } return oriented_collinear; }