Skip to content

Commit

Permalink
fixed getBB( pair) whatever the points, changed size() function behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
skramm committed Feb 1, 2025
1 parent f04f06f commit afd0fd5
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 77 deletions.
3 changes: 2 additions & 1 deletion docs/homog2d_history.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ See [Release page](https://github.com/skramm/homog2d/releases).
- polygon minimization

- current master branch
- (nil)
- changed behavior of the `size()` member and free functions:
now all of these return the number of points that the primitive has, as a `size_t` type, see [details here](homog2d_manual.md#p_commonf).

- [v2.12](https://github.com/skramm/homog2d/releases/tag/v2.12), released on 2025-01-26
- **heavy architectural change**: runtime polymorphism is now achieved in a more modern way, using `std::variant`, [see here](homog2d_manual.md#section_rtp).
Expand Down
49 changes: 42 additions & 7 deletions docs/homog2d_manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -582,13 +582,6 @@ auto a = rect.area(); // or: area(rect);
auto l = rect.length(); // or: length(rect);
```

You can gets its size as a pair of values (member function or free function),
with the width as `first` element and height as `second` element:
```C++
FRect rect;
auto s1 = rect.size(); // or: size(rect);
```

It is possible to translate the rectangle using some dx,dy offset:
```C++
FRect rect;
Expand Down Expand Up @@ -1115,6 +1108,48 @@ bool b2 = isCircle( ell, 1E-15 );
```


### 3.6 - Common functions
<a name="p_commonf"></a>

All the types above share some common functions, that are also declared as virtual in the root class `Root`.
Thus, this enable classical pointer-based runtime polymorphism, [see here](#section_rtp).

All of these are `const`.
The names of theses functions are:

| Name | Return type |
|------------|-------------|
| `size()` | `size_t` |
| `area()` | `HOMOG2D_INUMTYPE` |
| `length()` | `HOMOG2D_INUMTYPE` |
| `type()` | `Type` [see here]() |
| `draw()` | `void` |


The `type()` function will return an enum value of type `Type` having one of these values:
`Point2d`, `Line2d`, `Segment`, `FRect`, `Circle`, `Ellipse`, `OPolyline`, `CPolyline`.
You can get a human-readable value ot the object type with `getString(Type)`:
```C++
Point2d pt;
std::cout << "type is " << getString( pt.type() );
```
(This example might sound silly but it can be useful in real-time polymorhism situations.)


The return value of the `size()` member function is as follows, for the different types.
They are declared as `constexpr`, except of course for the last 2.

| Type | Return Value |
|--------------|--------------|
| `Point2d` | 1 |
| `Line2d` | 1 |
| `Segment` | 2 |
| `FRect` | 4 |
| `Circle` | 1 |
| `Ellipse` | 1 |
| `OPolyline` | Nb of points |
| `CPolyline` | Nb of points |


## 4 - Homographies
<a name="matrix"></a>
Expand Down
141 changes: 101 additions & 40 deletions homog2d.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,8 @@ class Root
#endif
virtual HOMOG2D_INUMTYPE length() const = 0;
virtual HOMOG2D_INUMTYPE area() const = 0;
virtual Type type() const = 0;
virtual Type type() const = 0;
virtual size_t size() const = 0;

friend std::ostream& operator << ( std::ostream& f, const Root& p );
virtual ~Root() {}
Expand Down Expand Up @@ -1374,14 +1375,14 @@ class Matrix_: public Common<FPT>
matrix_t<FPT>& getRaw() { return _mdata; }
const matrix_t<FPT>& getRaw() const { return _mdata; }

/* template<typename T>
template<typename T>
void set( size_t r, size_t c, T v )
{
#ifndef HOMOG2D_NOCHECKS
HOMOG2D_CHECK_ROW_COL;
#endif
_mdata[r][c] = v;
}*/
}

const FPT& value( size_t r, size_t c ) const
{
Expand Down Expand Up @@ -1960,7 +1961,8 @@ template<typename T> struct HasArea<Ellipse_<T>> : std::true_type {};
template<typename T> struct HasArea<base::PolylineBase<typename typ::IsClosed,T>>: std::true_type {};

/// This one is used in base;;PolylineBase::isInside()
template<typename T> struct PolIsClosed : std::false_type {};
/// \todo 20250131: probably useless, check if this can be replaced byt some "if contexpr"
template<typename T> struct PolIsClosed : std::false_type {};
template<typename T> struct PolIsClosed<base::PolylineBase<typename typ::IsClosed,T>>: std::true_type {};


Expand Down Expand Up @@ -2189,6 +2191,12 @@ class Ellipse_: public detail::Matrix_<FPT>

/// \name attributes of ellipse
///@{

constexpr size_t size() const
{
return 1;
}

bool isCircle( HOMOG2D_INUMTYPE thres=1.E-10 ) const;
Point2d_<FPT> getCenter() const;
CPolyline_<FPT> getOBB() const;
Expand Down Expand Up @@ -2640,10 +2648,10 @@ class FRect_: public detail::Common<FPT>
HOMOG2D_INUMTYPE width() const { return _ptR2.getX() - _ptR1.getX(); }
HOMOG2D_INUMTYPE area() const { return height() * width(); }
HOMOG2D_INUMTYPE length() const { return 2.*height() + 2.*width(); }
/// Return size of rectangle in a std::pair<width, height>
std::pair<HOMOG2D_INUMTYPE,HOMOG2D_INUMTYPE> size() const

constexpr size_t size() const
{
return std::make_pair( width(), height() );
return 4;
}

/// Needed for getBB( pair of objects )
Expand Down Expand Up @@ -3161,6 +3169,11 @@ We need Sfinae because there is another 3-args constructor (x, y, radius as floa
const Point2d_<FPT>& center() const { return _center; }
const Point2d_<FPT>& getCenter() const { return _center; }

constexpr size_t size() const
{
return 1;
}

HOMOG2D_INUMTYPE area() const
{
return static_cast<HOMOG2D_INUMTYPE>(_radius) * _radius * M_PI;
Expand Down Expand Up @@ -3980,17 +3993,18 @@ Thus, we need the second one.
public:
Type type() const
{
return impl_type( detail::BaseHelper<LP>() );
if constexpr( std::is_same_v<LP,typ::IsPoint> )
return Type::Point2d;
else
return Type::Line2d;
}

private:
Type impl_type( const detail::BaseHelper<typename typ::IsPoint>& ) const
{
return Type::Point2d;
}
Type impl_type( const detail::BaseHelper<typename typ::IsLine>& ) const
size_t size() const
{
return Type::Line2d;
if constexpr( std::is_same_v<LP,typ::IsPoint> )
return 1;
else
return 0;
}

public:
Expand Down Expand Up @@ -4095,13 +4109,14 @@ Thus, we need the second one.
impl_moveTo( pt, detail::BaseHelper<LP>() );
}

#ifdef HOMOG2D_ENABLE_VRTP
/// Needed because of variant (\sa CommonType)
//#ifdef HOMOG2D_ENABLE_VRTP
/// Needed so the function getBB(T1,T2) builds, whatever the types
/// and because of variant (\sa CommonType)
FRect_<FPT> getBB() const
{
HOMOG2D_THROW_ERROR_1( "invalid call, Point/Line has no Bounding Box" );
}
#endif
//#endif

private:
template<typename ANY>
Expand Down Expand Up @@ -4987,6 +5002,18 @@ class Segment_: public detail::Common<FPT>
/// \name Attributes access
///@{

/// Needed so the function getBB(T1,T2) builds, whatever the types
/// and because of variant (\sa CommonType)
FRect_<FPT> getBB() const
{
HOMOG2D_THROW_ERROR_1( "invalid call, Segment has no Bounding Box" );
}

constexpr size_t size() const
{
return 2;
}

/// Get segment length
HOMOG2D_INUMTYPE length() const
{
Expand All @@ -5009,15 +5036,6 @@ in the range \f$ [0,\pi/2] \f$
{
return other.getAngle( this->getLine() );
}

#ifdef HOMOG2D_ENABLE_VRTP
/// Needed because of variant (\sa CommonType)
FRect_<FPT> getBB() const
{
HOMOG2D_THROW_ERROR_1( "invalid call, segment has no Bounding Box" );
}
#endif

///@}

/// \name Operators
Expand Down Expand Up @@ -5815,7 +5833,6 @@ class PolylineBase: public detail::Common<FPT>
public:
using FType = FPT;
using PType = PLT;
// using SType = typ::T_Polyline;
using SType = std::conditional<std::is_same_v<PLT,typ::IsClosed>,typ::T_CPol,typ::T_OPol>;

using detail::Common<FPT>::isInside;
Expand Down Expand Up @@ -9645,13 +9662,12 @@ rotate( T& prim, Rotate rot, const Point2d_<FPT>& refpt )
prim.rotate( rot, refpt );
}

/// Returns width, height of rectangle (free function)
/// \sa FRect_::size()
template<typename FPT>
std::pair<HOMOG2D_INUMTYPE,HOMOG2D_INUMTYPE>
size( const FRect_<FPT>& rect )
/// Returns size (nb of points) of object
template<typename T>
size_t
size( const T& e )
{
return rect.size();
return e.size();
}

/// Returns Bounding Box of Ellipse_ (free function)
Expand Down Expand Up @@ -9743,7 +9759,7 @@ getPointPair( const T& elem )
template<
typename T,
typename std::enable_if<
std::is_same<T,Segment_<typename T::FType>>::value
std::is_same_v<T,Segment_<typename T::FType>>
,T
>::type* = nullptr
>
Expand Down Expand Up @@ -9911,6 +9927,7 @@ getBB_CommonType( const std::vector<CommonType_<FPT>>& v_var )
} // namespace priv

#endif // HOMOG2D_ENABLE_VRTP

//------------------------------------------------------------------
/// Return Bounding Box of primitive or container holding primitives (free function)
/**
Expand Down Expand Up @@ -10029,20 +10046,58 @@ getBB( const PointPair2_<T1,T2>& pp1, const PointPair2_<T3,T4>& pp2 )
}

//------------------------------------------------------------------
/// Overload 1/3. This one is called if NONE of the args are a Line2d
/// Overload 1/3. This one is called if NONE of the args are a Line2d neither a POlyline
template<
typename T1,
typename T2,
typename std::enable_if<
(!std::is_same<T1,Line2d_<typename T1::FType>>::value && !std::is_same<T2,Line2d_<typename T2::FType>>::value)
,T1
typename std::enable_if<(
!std::is_same_v<T1,Line2d_<typename T1::FType>>
&& !std::is_same_v<T2,Line2d_<typename T2::FType>>
&& !std::is_same_v<typename T1::SType,typ::T_CPol>
&& !std::is_same_v<typename T1::SType,typ::T_OPol>
&& !std::is_same_v<typename T2::SType,typ::T_CPol>
&& !std::is_same_v<typename T2::SType,typ::T_OPol>
),T1
>::type* = nullptr
>
auto
getBB( const T1& elem1, const T2& elem2 )
{
HOMOG2D_START;
FRect_<typename T1::FType> out;

// std::cout << "TYPE 1=" << getString( elem1.type() ) << " TYPE 2=" << getString( elem2.type() ) << "\n";

bool isPoly_1 = false;
if( elem1.type() == Type::OPolyline || elem1.type() == Type::CPolyline )
isPoly_1 = true;

bool isPoly_2 = false;
if( elem2.type() == Type::OPolyline || elem2.type() == Type::CPolyline )
isPoly_1 = true;

auto siz_1 = elem1.size();
auto siz_2 = elem2.size();

if( isPoly_1 && isPoly_2 )
if( siz_1==0 && siz_2==0 )
HOMOG2D_THROW_ERROR_1( "unable to compute bounding box of two empty polyline objects" );

// we need to do that in two steps: first, copy return value into `out`, then return
// because the underlying floating point might not be the same for the two arguments.
if( isPoly_2 && siz_1==0 )
{
// std::cout << "isPoly_2 && isEmpty_1\n";
out = getBB( elem2 );
return out;
}
if( isPoly_1 && siz_2==0 )
{
// std::cout << "isPoly_1 && isEmpty_2\n";
out = getBB( elem1 );
return out;
}

try
{
out = getBB(
Expand All @@ -10058,7 +10113,9 @@ getBB( const T1& elem1, const T2& elem2 )
return out;
}

#if 0
/// Overload 2/3. Called if 2 polyline objects
/// REMOVE: it works only if BOTH are polyline, if we have, say a polyline and a point, it will fail
template<
typename T1,
typename T2,
Expand Down Expand Up @@ -10090,6 +10147,8 @@ getBB( const T1& p1, const T2& p2 )
ppair::getPointPair( p2 )
);
}
#endif

//------------------------------------------------------------------
/// Overload 3/3. Called if one of the args is a Line2d (=> no build!)
template<
Expand Down Expand Up @@ -11669,7 +11728,9 @@ void print( std::ostream& f )
}
\endcode
*/
std::ostream& operator << ( std::ostream& f, const Root& p )
inline
std::ostream&
operator << ( std::ostream& f, const Root& p )
{
f << "type="<< getString( p.type() ) << std::endl;
switch( p.type() )
Expand Down
Loading

0 comments on commit afd0fd5

Please sign in to comment.