diff --git a/include/geode/geometry/aabb.h b/include/geode/geometry/aabb.h index 3c15438af..5cb85d887 100644 --- a/include/geode/geometry/aabb.h +++ b/include/geode/geometry/aabb.h @@ -164,6 +164,23 @@ namespace geode void compute_ray_element_bbox_intersections( const Ray< dimension >& ray, EvalIntersection& action ) const; + /*! + * @brief Computes the intersections between a given infinite line and + * all element boxes. + * @param[in] line The line to test. + * @param[in] action The functor to run when a box is intersected by the + * line. + * @tparam EvalIntersection this functor should have an operator() + * defined like this: + * void operator()( index_t cur_element_box ) ; + * @note the operator define what to do with the box \p cur_element_box + * if it is intersected by the \p line. + */ + template < class EvalIntersection > + void compute_line_element_bbox_intersections( + const InfiniteLine< dimension >& line, + EvalIntersection& action ) const; + private: IMPLEMENTATION_MEMBER( impl_ ); }; diff --git a/include/geode/geometry/basic_objects/infinite_line.h b/include/geode/geometry/basic_objects/infinite_line.h index 17a11013a..42778ca92 100644 --- a/include/geode/geometry/basic_objects/infinite_line.h +++ b/include/geode/geometry/basic_objects/infinite_line.h @@ -29,6 +29,7 @@ namespace geode { FORWARD_DECLARATION_DIMENSION_CLASS( OwnerInfiniteLine ); + FORWARD_DECLARATION_DIMENSION_CLASS( OwnerRay ); FORWARD_DECLARATION_DIMENSION_CLASS( Point ); template < typename PointType, index_t dimension > class GenericSegment; @@ -64,6 +65,7 @@ namespace geode protected: GenericInfiniteLine( const OwnerInfiniteLine< dimension >& other ); + GenericInfiniteLine( const OwnerRay< dimension >& other ); private: PointType origin_; @@ -89,8 +91,22 @@ namespace geode OwnerInfiniteLine< dimension >&& other ); }; ALIAS_1D_AND_2D_AND_3D( OwnerInfiniteLine ); + template < index_t dimension > - using OwnerRay = OwnerInfiniteLine< dimension >; + class OwnerRay : public GenericInfiniteLine< Point< dimension >, dimension > + { + using Base = GenericInfiniteLine< Point< dimension >, dimension >; + + public: + explicit OwnerRay( const Vector< dimension >& direction, + const Point< dimension >& origin ); + + OwnerRay( const Segment< dimension >& segment ); + OwnerRay( const OwnerRay< dimension >& other ); + OwnerRay< dimension >& operator=( const OwnerRay< dimension >& other ); + OwnerRay( OwnerRay< dimension >&& other ); + OwnerRay< dimension >& operator=( OwnerRay< dimension >&& other ); + }; ALIAS_1D_AND_2D_AND_3D( OwnerRay ); template < index_t dimension > @@ -113,7 +129,22 @@ namespace geode InfiniteLine< dimension >&& other ); }; ALIAS_1D_AND_2D_AND_3D( InfiniteLine ); + template < index_t dimension > - using Ray = InfiniteLine< dimension >; + class Ray : public GenericInfiniteLine< RefPoint< dimension >, dimension > + { + using Base = GenericInfiniteLine< RefPoint< dimension >, dimension >; + + public: + Ray( const Vector< dimension >& direction, + const Point< dimension >& origin ); + Ray( const Segment< dimension >& segment ); + + Ray( const Ray< dimension >& other ); + Ray( const OwnerRay< dimension >& other ); + Ray< dimension >& operator=( const Ray< dimension >& other ); + Ray( Ray< dimension >&& other ); + Ray< dimension >& operator=( Ray< dimension >&& other ); + }; ALIAS_1D_AND_2D_AND_3D( Ray ); } // namespace geode diff --git a/include/geode/geometry/bounding_box.h b/include/geode/geometry/bounding_box.h index 71022b271..6b7a9dc28 100644 --- a/include/geode/geometry/bounding_box.h +++ b/include/geode/geometry/bounding_box.h @@ -59,6 +59,8 @@ namespace geode bool intersects( const Ray< dimension >& ray ) const; + bool intersects( const InfiniteLine< dimension >& line ) const; + /*! * Returns the distance between the point and the box. * If the point is inside the box, the distance is negative. diff --git a/include/geode/geometry/detail/aabb_impl.h b/include/geode/geometry/detail/aabb_impl.h index eb9fa5f07..f1ea3d39c 100644 --- a/include/geode/geometry/detail/aabb_impl.h +++ b/include/geode/geometry/detail/aabb_impl.h @@ -98,14 +98,14 @@ namespace geode index_t element_end, const ACTION& action ) const; - template < class ACTION > + template < typename ACTION > void bbox_intersect_recursive( const BoundingBox< dimension >& box, index_t node_index, index_t element_begin, index_t element_end, ACTION& action ) const; - template < class ACTION > + template < typename ACTION > void self_intersect_recursive( index_t node_index1, index_t element_begin1, index_t element_end1, @@ -114,7 +114,7 @@ namespace geode index_t element_end2, ACTION& action ) const; - template < class ACTION > + template < typename ACTION > void other_intersect_recursive( index_t node_index1, index_t element_begin1, index_t element_end1, @@ -124,8 +124,8 @@ namespace geode index_t element_end2, ACTION& action ) const; - template < class ACTION > - void ray_intersect_recursive( const Ray< dimension >& ray, + template < typename Line, typename ACTION > + void line_intersect_recursive( const Line& line, index_t node_index, index_t element_begin, index_t element_end, @@ -209,10 +209,23 @@ namespace geode { return; } - impl_->ray_intersect_recursive( + impl_->line_intersect_recursive( ray, Impl::ROOT_INDEX, 0, nb_bboxes(), action ); } + template < index_t dimension > + template < class EvalIntersection > + void AABBTree< dimension >::compute_line_element_bbox_intersections( + const InfiniteLine< dimension >& line, EvalIntersection& action ) const + { + if( nb_bboxes() == 0 ) + { + return; + } + impl_->line_intersect_recursive( + line, Impl::ROOT_INDEX, 0, nb_bboxes(), action ); + } + template < index_t dimension > template < typename ACTION > void AABBTree< dimension >::Impl::closest_element_box_recursive( @@ -259,13 +272,13 @@ namespace geode { if( distance_left < distance ) { - closest_element_box_recursive< ACTION >( query, nearest_box, + closest_element_box_recursive( query, nearest_box, nearest_point, distance, it.child_left, box_begin, it.middle_box, action ); } if( distance_right < distance ) { - closest_element_box_recursive< ACTION >( query, nearest_box, + closest_element_box_recursive( query, nearest_box, nearest_point, distance, it.child_right, it.middle_box, box_end, action ); } @@ -274,13 +287,13 @@ namespace geode { if( distance_right < distance ) { - closest_element_box_recursive< ACTION >( query, nearest_box, + closest_element_box_recursive( query, nearest_box, nearest_point, distance, it.child_right, it.middle_box, box_end, action ); } if( distance_left < distance ) { - closest_element_box_recursive< ACTION >( query, nearest_box, + closest_element_box_recursive( query, nearest_box, nearest_point, distance, it.child_left, box_begin, it.middle_box, action ); } @@ -314,14 +327,14 @@ namespace geode const auto it = get_recursive_iterators( node_index, element_begin, element_end ); - bbox_intersect_recursive< ACTION >( + bbox_intersect_recursive( box, it.child_left, element_begin, it.middle_box, action ); - bbox_intersect_recursive< ACTION >( + bbox_intersect_recursive( box, it.child_right, it.middle_box, element_end, action ); } template < index_t dimension > - template < class ACTION > + template < typename ACTION > void AABBTree< dimension >::Impl::self_intersect_recursive( index_t node_index1, index_t element_begin1, @@ -372,28 +385,26 @@ namespace geode { const auto it = get_recursive_iterators( node_index2, element_begin2, element_end2 ); - self_intersect_recursive< ACTION >( node_index1, element_begin1, - element_end1, it.child_left, element_begin2, it.middle_box, - action ); - self_intersect_recursive< ACTION >( node_index1, element_begin1, - element_end1, it.child_right, it.middle_box, element_end2, - action ); + self_intersect_recursive( node_index1, element_begin1, element_end1, + it.child_left, element_begin2, it.middle_box, action ); + self_intersect_recursive( node_index1, element_begin1, element_end1, + it.child_right, it.middle_box, element_end2, action ); } else { const auto it = get_recursive_iterators( node_index1, element_begin1, element_end1 ); - self_intersect_recursive< ACTION >( it.child_left, element_begin1, + self_intersect_recursive( it.child_left, element_begin1, it.middle_box, node_index2, element_begin2, element_end2, action ); - self_intersect_recursive< ACTION >( it.child_right, it.middle_box, + self_intersect_recursive( it.child_right, it.middle_box, element_end1, node_index2, element_begin2, element_end2, action ); } } template < index_t dimension > - template < class ACTION > + template < typename ACTION > void AABBTree< dimension >::Impl::other_intersect_recursive( index_t node_index1, index_t element_begin1, @@ -433,10 +444,10 @@ namespace geode { const auto it = get_recursive_iterators( node_index2, element_begin2, element_end2 ); - other_intersect_recursive< ACTION >( node_index1, element_begin1, + other_intersect_recursive( node_index1, element_begin1, element_end1, other_tree, it.child_left, element_begin2, it.middle_box, action ); - other_intersect_recursive< ACTION >( node_index1, element_begin1, + other_intersect_recursive( node_index1, element_begin1, element_end1, other_tree, it.child_right, it.middle_box, element_end2, action ); } @@ -444,19 +455,19 @@ namespace geode { const auto it = get_recursive_iterators( node_index1, element_begin1, element_end1 ); - other_intersect_recursive< ACTION >( it.child_left, element_begin1, + other_intersect_recursive( it.child_left, element_begin1, it.middle_box, other_tree, node_index2, element_begin2, element_end2, action ); - other_intersect_recursive< ACTION >( it.child_right, it.middle_box, + other_intersect_recursive( it.child_right, it.middle_box, element_end1, other_tree, node_index2, element_begin2, element_end2, action ); } } template < index_t dimension > - template < typename ACTION > - void AABBTree< dimension >::Impl::ray_intersect_recursive( - const Ray< dimension >& ray, + template < typename Line, typename ACTION > + void AABBTree< dimension >::Impl::line_intersect_recursive( + const Line& line, index_t node_index, index_t element_begin, index_t element_end, @@ -467,7 +478,7 @@ namespace geode element_begin != element_end, "No iteration allowed start == end" ); // Prune sub-tree that does not have intersection - if( !node( node_index ).intersects( ray ) ) + if( !node( node_index ).intersects( line ) ) { return; } @@ -480,9 +491,9 @@ namespace geode const auto it = get_recursive_iterators( node_index, element_begin, element_end ); - ray_intersect_recursive< ACTION >( - ray, it.child_left, element_begin, it.middle_box, action ); - ray_intersect_recursive< ACTION >( - ray, it.child_right, it.middle_box, element_end, action ); + line_intersect_recursive( + line, it.child_left, element_begin, it.middle_box, action ); + line_intersect_recursive( + line, it.child_right, it.middle_box, element_end, action ); } } // namespace geode diff --git a/src/geode/geometry/basic_objects/infinite_line.cpp b/src/geode/geometry/basic_objects/infinite_line.cpp index 10343e8c5..30406ff4b 100644 --- a/src/geode/geometry/basic_objects/infinite_line.cpp +++ b/src/geode/geometry/basic_objects/infinite_line.cpp @@ -89,6 +89,12 @@ namespace geode : origin_( other.origin() ), direction_( other.direction() ) { } + template < typename PointType, index_t dimension > + GenericInfiniteLine< PointType, dimension >::GenericInfiniteLine( + const OwnerRay< dimension >& other ) + : origin_( other.origin() ), direction_( other.direction() ) + { + } template < index_t dimension > OwnerInfiniteLine< dimension >::OwnerInfiniteLine( @@ -174,6 +180,79 @@ namespace geode return *this; } + template < index_t dimension > + OwnerRay< dimension >::OwnerRay( + const Vector< dimension >& direction, const Point< dimension >& origin ) + : Base( direction, origin ) + { + } + template < index_t dimension > + OwnerRay< dimension >::OwnerRay( const Segment< dimension >& segment ) + : OwnerRay( segment.normalized_direction(), segment.vertices()[0] ) + { + } + template < index_t dimension > + OwnerRay< dimension >::OwnerRay( const OwnerRay< dimension >& other ) + : Base( other ) + { + } + template < index_t dimension > + OwnerRay< dimension >& OwnerRay< dimension >::operator=( + const OwnerRay< dimension >& other ) + { + Base::operator=( other ); + return *this; + } + template < index_t dimension > + OwnerRay< dimension >::OwnerRay( OwnerRay< dimension >&& other ) + : Base( other ) + { + } + template < index_t dimension > + OwnerRay< dimension >& OwnerRay< dimension >::operator=( + OwnerRay< dimension >&& other ) + { + Base::operator=( other ); + return *this; + } + + template < index_t dimension > + Ray< dimension >::Ray( + const Vector< dimension >& direction, const Point< dimension >& origin ) + : Base( direction, origin ) + { + } + template < index_t dimension > + Ray< dimension >::Ray( const Segment< dimension >& segment ) + : Ray( segment.normalized_direction(), segment.vertices()[0] ) + { + } + template < index_t dimension > + Ray< dimension >::Ray( const Ray< dimension >& other ) : Base( other ) + { + } + template < index_t dimension > + Ray< dimension >::Ray( const OwnerRay< dimension >& other ) : Base( other ) + { + } + template < index_t dimension > + Ray< dimension >& Ray< dimension >::operator=( + const Ray< dimension >& other ) + { + Base::operator=( other ); + return *this; + } + template < index_t dimension > + Ray< dimension >::Ray( Ray< dimension >&& other ) : Base( other ) + { + } + template < index_t dimension > + Ray< dimension >& Ray< dimension >::operator=( Ray< dimension >&& other ) + { + Base::operator=( other ); + return *this; + } + template class opengeode_geometry_api GenericInfiniteLine< Point< 1 >, 1 >; template class opengeode_geometry_api GenericInfiniteLine< Point< 2 >, 2 >; template class opengeode_geometry_api GenericInfiniteLine< Point< 3 >, 3 >; @@ -189,4 +268,10 @@ namespace geode template class opengeode_geometry_api InfiniteLine< 1 >; template class opengeode_geometry_api InfiniteLine< 2 >; template class opengeode_geometry_api InfiniteLine< 3 >; + template class opengeode_geometry_api OwnerRay< 1 >; + template class opengeode_geometry_api OwnerRay< 2 >; + template class opengeode_geometry_api OwnerRay< 3 >; + template class opengeode_geometry_api Ray< 1 >; + template class opengeode_geometry_api Ray< 2 >; + template class opengeode_geometry_api Ray< 3 >; } // namespace geode diff --git a/src/geode/geometry/bounding_box.cpp b/src/geode/geometry/bounding_box.cpp index c316031a1..a8fad75c2 100644 --- a/src/geode/geometry/bounding_box.cpp +++ b/src/geode/geometry/bounding_box.cpp @@ -123,6 +123,11 @@ namespace geode return line_intersects( ray ); } + bool intersects( const InfiniteLine< dimension >& line ) const + { + return line_intersects( line ); + } + double signed_distance( const Point< dimension >& point ) const { bool inside{ true }; @@ -168,7 +173,9 @@ namespace geode } private: - bool line_intersects( const InfiniteLine< dimension >& line ) const; + bool line_intersects( + const GenericInfiniteLine< RefPoint< dimension >, dimension >& + line ) const; private: Point< dimension > min_; @@ -177,7 +184,7 @@ namespace geode template <> bool BoundingBox< 3 >::Impl::line_intersects( - const InfiniteLine3D& line ) const + const GenericInfiniteLine< RefPoint< 3 >, 3 >& line ) const { const auto box_half_extent = diagonal() / 2.; const auto line_translated_origin = line.origin() - center(); @@ -207,7 +214,7 @@ namespace geode template <> bool BoundingBox< 2 >::Impl::line_intersects( - const InfiniteLine2D& line ) const + const GenericInfiniteLine< RefPoint< 2 >, 2 >& line ) const { const auto box_center = center(); const auto box_half_extent = diagonal() / 2.; @@ -223,7 +230,7 @@ namespace geode template <> bool BoundingBox< 1 >::Impl::line_intersects( - const InfiniteLine1D& line ) const + const GenericInfiniteLine< RefPoint< 1 >, 1 >& line ) const { if( diagonal().dot( line.direction() ) > 0 ) { @@ -316,6 +323,13 @@ namespace geode return impl_->intersects( ray ); } + template < index_t dimension > + bool BoundingBox< dimension >::intersects( + const InfiniteLine< dimension >& line ) const + { + return impl_->intersects( line ); + } + template < index_t dimension > Point< dimension > BoundingBox< dimension >::center() const {