Example #1
0
		//! 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 );
		}
Example #2
0
		//! 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;
	}