Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Bbox class with dimension as parameter #8258

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Kernel_23/doc/Kernel_23/Concepts/FunctionObjectConcepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -3896,7 +3896,7 @@ class ConstructBbox_3 {
/*!
returns a bounding box of `i`.
*/
CGAL::Bbox_3 operator()(const Kernel::Iso_Cuboid_3
CGAL::Bbox_3 operator()(const Kernel::Iso_cuboid_3
&i);

/*!
Expand Down
181 changes: 181 additions & 0 deletions Kernel_23/include/CGAL/Bbox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// Copyright (c) 2022 Institut Géographique National - IGN (France)
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Mathieu Brédif

#ifndef CGAL_BBOX_H
#define CGAL_BBOX_H

#include <boost/config.hpp> // defines BOOST_PREVENT_MACRO_SUBSTITUTION
#include <stddef.h>
#include <limits>
#include <array>
#include <iostream>
#include <iterator>
#include <CGAL/assertions.h>
#include <CGAL/Dimension.h>

namespace CGAL {
namespace Impl {

template<typename Container, typename Derived>
class Bbox
{
protected:
typedef typename Container::value_type T;
Container min_values;
Container max_values;

public:
Bbox& operator+=(const Bbox& bbox)
{
CGAL_assertion(min_values.size() == 0 || min_values.size() == bbox.min_values.size());
if(min_values.size() == 0){
*this = bbox;
}
int dim = bbox.min_values.size();
for(int i=0; i<dim; ++i)
{
if(min_values[i] > bbox.min_values[i]) min_values[i] = bbox.min_values[i];
if(max_values[i] < bbox.max_values[i]) max_values[i] = bbox.max_values[i];
}
return *this;
}

inline int dimension() const
{
return static_cast<const Derived*>(this)->dimension();
}

inline T min BOOST_PREVENT_MACRO_SUBSTITUTION (int i) const
{
return min_values[i];
}

inline T max BOOST_PREVENT_MACRO_SUBSTITUTION (int i) const
{
return max_values[i];
}

inline T& min BOOST_PREVENT_MACRO_SUBSTITUTION (int i)
{
return min_values[i];
}

inline T& max BOOST_PREVENT_MACRO_SUBSTITUTION (int i)
{
return max_values[i];
}

inline T measure() const {
T result = max_values[0] - min_values[0];
if (result <= 0) return 0;
for(int i=1; i<dimension(); ++i)
result *= max_values[i] - min_values[i];
return result;
}

inline T intersection_measure(const Bbox& bbox) const {
CGAL_assertion(dimension() == bbox.dimension());
T result = 1;
for(int i=0; i<dimension(); ++i) {
result *= (std::min)((max)(i), (bbox.max)(i)) -
(std::max)((min)(i), (bbox.min)(i));
if (result <= 0) return 0;
}
return result;
}

bool operator==(const Bbox& bbox) const {
for(int i=0; i<dimension(); ++i)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mbredif don't we have to check that the dimensions are equal?

if (min_values[i] != bbox.min_values[i] || max_values[i] != bbox.max_values[i])
return false;
return true;
}

bool operator!=(const Bbox& bbox) const { return !operator==(bbox); }

protected:
void init(int d, T range = -std::numeric_limits<T>::infinity()) {
for(int i=0; i<d; ++i)
{
min_values[i] = -range;
max_values[i] = range;
}
}

template <typename I>
void init(int d, I b, I e) {
afabri marked this conversation as resolved.
Show resolved Hide resolved
CGAL_assertion(d == std::distance(b,e));
for(int i=0; i<d; ++i,++b)
{
min_values[i] = (*b).first;
max_values[i] = (*b).second;
}
}
};

}

template <typename Di, typename T>
class Bbox;

// A fixed D-dimensional axis aligned box
template<int N, typename T>
class Bbox<Dimension_tag<N>, T> : public Impl::Bbox<std::array<T, N>, Bbox<Dimension_tag<N>,T>>
{
enum { D = N };
public:
inline constexpr int dimension() const { return D; }
Bbox(int d = 0 ) { CGAL_assertion(d==N || d==0); this->init(d ); }
Bbox(int d, const T& range) { CGAL_assertion(d==N || d==0); this->init(d, range); }
template <typename I>
Bbox(int d, I b, I e) { CGAL_assertion(d==N || d==0); this->init(d, b, e); }
};

// A dynamic D-dimensional axis aligned box
template<typename T>
class Bbox<Dynamic_dimension_tag,T> : public Impl::Bbox<std::vector<T>, Bbox<Dynamic_dimension_tag,T>>
{
public:
inline int dimension() const { return this->min_values.size(); }
Bbox(int d = 0 ) { init_values(d); this->init(d ); }
Bbox(int d, const T& range) { init_values(d); this->init(d, range); }
template <typename I>
Bbox(int d, I b, I e) { init_values(d); this->init(d, b, e); }

protected:
void init_values(int d) {
this->min_values.resize(d);
this->max_values.resize(d);
Comment on lines +157 to +158
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a bit wasteful to use 2 containers of size d instead of one of size 2*d, but that's an implementation detail so it doesn't matter now.

}
};

template<typename Container, typename Derived>
std::ostream& operator<<(std::ostream& out, const Impl::Bbox<Container, Derived>& bbox)
{
int d = bbox.dimension();
for(int i=0; i<d; ++i)
out << (bbox.min)(i) << " " << (bbox.max)(i) << " ";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bbox_2/3 first print lower left and then upper right.

return out;
}

template<typename Container, typename Derived>
std::istream& operator>>(std::istream& in, Impl::Bbox<Container, Derived>& bbox)
{
int d = bbox.dimension();
for(int i=0; i<d; ++i)
in >> (bbox.min)(i) >> (bbox.max)(i);
return in;
}


} // namespace CGAL

#endif // CGAL_DDT_BBOX_H
17 changes: 17 additions & 0 deletions Kernel_23/test/Kernel_23/test_bbox.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/Bbox.h>

#include <vector>

Expand Down Expand Up @@ -78,4 +79,20 @@ int main()
assert( span.y_span() == 6);
assert( span.z_span() == 8);
}

{
//Dimension d
typedef CGAL::Bbox<CGAL::Dimension_tag<3>,double> BBox3;
BBox3 bb3(3), bb3a(3,1.0);
assert(bb3.dimension() == 3);
assert(bb3 != bb3a);
bb3 = bb3a;
assert(bb3 == bb3a);

std::array<std::pair<double,double>,3> coord = { std::make_pair(0.0, 0.0), std::make_pair(1.0, 1.1), std::make_pair(1.0, 20.0)};

BBox3 bb3b(3,coord.begin(), coord.end());

std::cout << bb3b << std::endl;
}
}
2 changes: 1 addition & 1 deletion Kernel_d/doc/Kernel_d/CGAL/Epeck_d.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ or `Dynamic_dimension_tag`. In the latter case, the dimension of the space is sp
\attention Only the interfaces specific to this class are listed below. Refer to the
concepts for the rest.

\attention Known bugs: the functor `Kernel_d::Intersect_d` is not yet implemented. `Kernel_d::Contained_in_affine_hull` assumes that the iterators refer to an affinely independent family. `Kernel_d::Orientation_d` only works for points, not vectors. Visual Studio 2015 is not supported.
\attention Known bugs: the functor `Kernel_d::Intersect_d` is not yet implemented. `Kernel_d::Contained_in_affine_hull_d` assumes that the iterators refer to an affinely independent family. `Kernel_d::Orientation_d` only works for points, not vectors. Visual Studio 2015 is not supported.

\attention This kernel requires the \ref thirdpartyEigen "Eigen" library.

Expand Down
2 changes: 1 addition & 1 deletion Kernel_d/doc/Kernel_d/CGAL/Epick_d.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ or `Dynamic_dimension_tag`. In the latter case, the dimension of the space is sp
\attention Only the interfaces specific to this class are listed below. Refer to the
concepts for the rest.

\attention Known bugs: the functor `Kernel_d::Intersect_d` is not yet implemented. `Kernel_d::Contained_in_affine_hull` assumes that the iterators refer to an affinely independent family. `Kernel_d::Orientation_d` only works for points, not vectors.
\attention Known bugs: the functor `Kernel_d::Intersect_d` is not yet implemented. `Kernel_d::Contained_in_affine_hull_d` assumes that the iterators refer to an affinely independent family. `Kernel_d::Orientation_d` only works for points, not vectors.

\attention This kernel requires the \ref thirdpartyEigen "Eigen" library.

Expand Down
2 changes: 2 additions & 0 deletions NewKernel_d/include/CGAL/NewKernel_d/Kernel_d_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ template <class Base_> struct Kernel_d_interface : public Base_ {
typedef typename Construct_cartesian_const_iterator_d::result_type Cartesian_const_iterator_d;
typedef typename Get_functor<Base, Squared_distance_tag>::type Squared_distance_d;
typedef typename Get_functor<Base, Squared_length_tag>::type Squared_length_d;
typedef typename Get_functor<Base, Construct_bbox_tag>::type Construct_bbox_d;
typedef typename Get_functor<Base, Scalar_product_tag>::type Scalar_product_d;
typedef typename Get_functor<Base, Affine_rank_tag>::type Affine_rank_d;
typedef typename Get_functor<Base, Affinely_independent_tag>::type Affinely_independent_d;
Expand Down Expand Up @@ -259,6 +260,7 @@ template <class Base_> struct Kernel_d_interface : public Base_ {
Compute_squared_radius_smallest_orthogonal_sphere_d compute_squared_radius_smallest_orthogonal_sphere_d_object()const{ return Compute_squared_radius_smallest_orthogonal_sphere_d(*this); }
Squared_distance_d squared_distance_d_object()const{ return Squared_distance_d(*this); }
Squared_length_d squared_length_d_object()const{ return Squared_length_d(*this); }
Construct_bbox_d construct_bbox_d_object()const{ return Construct_bbox_d(*this); }
Scalar_product_d scalar_product_d_object()const{ return Scalar_product_d(*this); }
Center_of_sphere_d center_of_sphere_d_object()const{ return Center_of_sphere_d(*this); }
Construct_circumcenter_d construct_circumcenter_d_object()const{ return Construct_circumcenter_d(*this); }
Expand Down
24 changes: 24 additions & 0 deletions NewKernel_d/include/CGAL/NewKernel_d/function_objects_cartesian.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <CGAL/NewKernel_d/utils.h>
#include <CGAL/Dimension.h>
#include <CGAL/Bbox.h>
#include <CGAL/Uncertain.h>
#include <CGAL/NewKernel_d/store_kernel.h>
#include <CGAL/type_traits/is_iterator.h>
Expand Down Expand Up @@ -1006,6 +1007,29 @@ template<class R_> struct Squared_length : private Store_kernel<R_> {

CGAL_KD_DEFAULT_FUNCTOR(Squared_length_tag,(CartesianDKernelFunctors::Squared_length<K>),(Vector_tag),(Construct_ttag<Vector_cartesian_const_iterator_tag>));

namespace CartesianDKernelFunctors {
template<class R_> struct Construct_bbox : private Store_kernel<R_> {
CGAL_FUNCTOR_INIT_STORE(Construct_bbox)
typedef R_ R;
typedef typename R::Dimension Dimension;
typedef typename Get_type<R, RT_tag>::type RT;
typedef typename Get_type<R, Point_tag>::type Point;
typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::type CI;

typedef Bbox<Dimension,double> result_type;
typedef Point argument_type;
result_type operator()(Point const&a)const{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, is it likely to stick to just this function, or do you expect to add overloads for Segment, Sphere, Iso_box, etc? I am asking because ideally (I stopped before making things consistent), overload resolution should happen in Kernel_d_interface, and dispatch to different non-overloaded functors like Bbox_from_point, Bbox_from_segment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be natural to generalize. We started this only for the Frechet Distance submission, where we only deal with points.

CI ci(this->kernel());
typename Real_embeddable_traits<RT>::To_interval f;
typename Get_functor<R, Point_dimension_tag>::type pd(this->kernel());
return result_type(pd(a), make_transforming_iterator(ci(a,Begin_tag()),f), make_transforming_iterator(ci(a,End_tag())), f);
}
};
}

CGAL_KD_DEFAULT_FUNCTOR(Construct_bbox_tag,(CartesianDKernelFunctors::Construct_bbox<K>),(Point_tag),(Construct_ttag<Point_cartesian_const_iterator_tag>));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mglisse do you have any doc for the macro CGAL_KD_DEFAULT_FUNCTOR. I'm pretty sure this line is incorrect but I don't know how to fix it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line looks ok to me. You have the tag, the class, the required objects, the required other functors, that's it. Ah, maybe you are missing Point_dimension_tag in the last list (I am not sure this list is really used currently).



namespace CartesianDKernelFunctors {
template<class R_> struct Squared_distance_to_origin : private Store_kernel<R_> {
CGAL_FUNCTOR_INIT_STORE(Squared_distance_to_origin)
Expand Down
1 change: 1 addition & 0 deletions NewKernel_d/include/CGAL/NewKernel_d/functor_tags.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ namespace CGAL {
CGAL_DECL_COMPUTE(Squared_distance);
CGAL_DECL_COMPUTE(Squared_distance_to_origin);
CGAL_DECL_COMPUTE(Squared_length);
CGAL_DECL_COMPUTE(Construct_bbox);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes more sense as CGAL_DECL_MISC. "Compute" is for things that return a Lazy_exact_nt in Epeck_d.
And then Lazy_cartesian needs something similar to Point_dimension_tag, assuming that the Bbox is supposed to be built from the approximate object (maybe merge the cases Point_dimension_tag, Vector_dimension_tag, and this new one in a partial specialization struct Functor<T,D,Misc_tag>?)

CGAL_DECL_COMPUTE(Squared_radius);
CGAL_DECL_COMPUTE(Squared_circumradius);
CGAL_DECL_COMPUTE(Scalar_product);
Expand Down
3 changes: 3 additions & 0 deletions NewKernel_d/test/NewKernel_d/Epick_d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ void test2(){
typedef typename K1::Construct_weighted_point_d CWP;
typedef typename K1::Power_side_of_bounded_power_sphere_d PSBPS;
typedef typename K1::Compute_squared_radius_smallest_orthogonal_sphere_d CSRSOS;
typedef typename K1::Construct_bbox_d CB;
//typedef typename K1::Point_drop_weight_d PDW;
typedef CP PDW;
typedef typename K1::Compute_weight_d PW;
Expand All @@ -151,6 +152,7 @@ void test2(){
(2)
#endif
;
CB cb Kinit(construct_bbox_d_object);
CP cp Kinit(construct_point_d_object);
CV cv Kinit(construct_vector_d_object);
CCI ci Kinit(construct_cartesian_const_iterator_d_object);
Expand Down Expand Up @@ -217,6 +219,7 @@ void test2(){
CGAL_USE(cr);
using std::abs;
P a=cp(3,4);
CGAL::Bbox<CGAL::Dimension_tag<2>,double> bb2 = cb(a);
assert(pd(a)==2);
assert(pv(a)[1]==4);
P b=vp(cv(5,6,7));
Expand Down
Loading