Skip to content

Commit

Permalink
Merge branch 'master' of github.com:skramm/homog2d
Browse files Browse the repository at this point in the history
  • Loading branch information
skramm committed Feb 3, 2025
2 parents a18311f + b72e094 commit 6217e09
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 32 deletions.
8 changes: 6 additions & 2 deletions docs/homog2d_devinfo.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ The makefile then compiles it and runs it.

## 4 - Code details

### 4.1 - Partial template implementation trick
### 4.1 - Partial template implementation tricks

To be able to templatize all the code on the root numerical data type (float, double, ...), we implement some trick.
As the `LPBase` class is already templatized on the type (`typ::IsPoint` or `typ::IsLine`),
Expand All @@ -95,8 +95,12 @@ it is there just so that the compiler can select the correct overload.

The different implementations are written as two `impl_` private functions that are templated by the numerical data type.
If the situation only makes sense for one of the types (for example `getAngle()` cannot be considered for two points), then
the implementation of that type only holds a `static_assert`, so that can be catched at build time.
the implementation of that type only holds a `static_assert`, so that error can be catched at build time.

This is mostly used with the three "base" classes:
- `base::LPBase`, specialized as `Point2d_` and `Line2d_`
- `base::PolylineBase`specialized as `CPolyline_` and `OPolyline`
- `base::SegVec`, specialized as `Segment_` and `OSegment_`

### 4.2 - Common classes and polymorphism

Expand Down
28 changes: 16 additions & 12 deletions docs/homog2d_manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,23 +369,23 @@ On this figure, you can see three combinations of bounding boxes for some object
![getbb1b](img/getbb1b.svg)
[source](../misc/figures_src/src/getbb1.cpp)

### 3.1 - Segments and vectors
### 3.1 - Segments
<a name="p_segment"></a>

This library provides these closely related two types.
They both share the same underlying type (a pair of points).
The difference between them is that a vector is **oriented**, while a segment is not.
This library provides two types modelling segments that both share the same underlying type (a pair of points),
named `Segment` and `OSegment`
The difference between them is that a `OSegment` is **oriented**, while a `Segment` is not.

Usage is straightforward:
Usage is straightforward, and is similar for both types:
```C++
Segment s1( Point2d(12,34), Point2d(45,67) );
Segment s2; // default value
std::cout << s2; // prints "(0,0) - (1,1)"
s2.set( Point2d(12,34), Point2d(45,67) );
```
You can also build theses by giving the 4 coordinates, x1,y1 and x2, y2 of the two points.
The only constraint is that they must be all of the same type (no int/float/double mix):
You can also build theses by giving the 4 coordinates, x1,y1 and x2, y2 of the two points,
that may even be of different types (float/double/...).
```C++
Segment s1( x1, y1, x2, y2 );
```
Expand All @@ -404,11 +404,15 @@ s1.translate( dx, dy );
```

You can get the pair of points (as an `std::pair`) with `getPts()`.
Internally, the points are stored with the "smallest" one as first (using x coordinate, or, if equal, using y coordinate):
```C++
Segment s1( Point2d(100,100), Point2d(10,10) );
auto pair = s1.getPts();
std::cout << pair.first; // will print (10,10)
For type `Segment`, the points are stored onternally with the "smallest" one as first (using x coordinate, or, if equal, using y coordinate).
For type `OSegment`, there as stored as is:
```C++
Segment s1( Point2d(100,100), Point2d(10,20) );
OSegment s2( Point2d(100,100), Point2d(10,20) );
auto pair1 = s1.getPts();
auto pair2 = s2.getPts();
std::cout << pair1.first; // will print (10,20)
std::cout << pair2.first; // will print (100,100)
```
Many operations available with lines apply to segments too:
Expand Down
56 changes: 38 additions & 18 deletions homog2d.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5000,47 +5000,64 @@ class SegVec: public detail::Common<FPT>
/// Default constructor: initializes segment to (0,0)--(1,1)
SegVec(): _ptS2(1.,1.)
{}
/// Constructor 2: build segment from two points
SegVec( Point2d_<FPT> p1, Point2d_<FPT> p2 )

/// Constructor 2: build segment from two points, can hold different FP types
/**
Please note that the source (points) floating-point type is lost
*/
template<typename FP1,typename FP2>
SegVec( Point2d_<FP1> p1, Point2d_<FP2> p2 )
: _ptS1(p1), _ptS2(p2)
{
#ifndef HOMOG2D_NOCHECKS
if( p1 == p2 )
HOMOG2D_THROW_ERROR_1( "cannot build a segment/vector with two identical points: " << p1 << " and " << p2 );
HOMOG2D_THROW_ERROR_1( "cannot build a segment with two identical points: " << p1 << " and " << p2 );
#endif
if constexpr( std::is_same_v<SV,typ::IsSegment> )
priv::fix_order( _ptS1, _ptS2 );
}

/// Constructor 3: build segment from two points coordinates, calls constructor 2
template<typename T>
SegVec( T x1, T y1, T x2, T y2 )
template<typename FP1,typename FP2,typename FP3,typename FP4>
SegVec( FP1 x1, FP2 y1, FP3 x2, FP4 y2 )
: SegVec( Point2d_<FPT>(x1,y1), Point2d_<FPT>(x2,y2) )
{
HOMOG2D_CHECK_IS_NUMBER(T);
HOMOG2D_CHECK_IS_NUMBER(FP1);
HOMOG2D_CHECK_IS_NUMBER(FP2);
HOMOG2D_CHECK_IS_NUMBER(FP3);
HOMOG2D_CHECK_IS_NUMBER(FP4);
}

/// Constructor 4: build segment from pair of points
SegVec( const PointPair1_<FPT>& ppts )
template<typename FP1,typename FP2>
SegVec( const PointPair2_<FP1,FP2>& ppts )
: SegVec(ppts.first, ppts.second)
{}

/// Copy-Constructor
/// Copy-Constructor, behavior depends on concrete types
/**
TODO:
- OSegment(OSegment): OK
- Segment(OSegment): OK, but loose orientation
- Segment(Segment): OK
- OSegment(Segment): throws, because orientation would be arbitrary
*/
template<typename SV2,typename FPT2>
SegVec( const SegVec<SV2,FPT2>& other )
: _ptS1(other._ptS1), _ptS2(other._ptS2)
{
if constexpr( std::is_same_v<SV2,typ::IsSegment> )
priv::fix_order( _ptS1, _ptS2 );
}

///@}

/// \name Modifying functions
///@{

/// Setter
template<typename FPT2>
void set( const Point2d_<FPT>& p1, const Point2d_<FPT2>& p2 )
template<typename FP1,typename FP2>
void set( const Point2d_<FP1>& p1, const Point2d_<FP2>& p2 )
{
#ifndef HOMOG2D_NOCHECKS
if( p1 == p2 )
Expand All @@ -5052,18 +5069,22 @@ class SegVec: public detail::Common<FPT>
priv::fix_order( _ptS1, _ptS2 );
}

/// Setter from a std::pair (points need to be of same underlying type)
template<typename FPT2>
void set( const PointPair1_<FPT2>& ppts )
/// Setter from a std::pair
template<typename FP1,typename FP2>
void set( const PointPair2_<FP1,FP2>& ppts )
{
set( ppts.first, ppts.second );
}

/// Setter from 4 raw point coordinates
template<typename FPT2>
void set( FPT2 x1, FPT2 y1, FPT2 x2, FPT2 y2 )
template<typename FP1,typename FP2,typename FP3,typename FP4>
void set( FP1 x1, FP2 y1, FP3 x2, FP4 y2 )
{
set( Point2d_<FPT2>(x1,y1), Point2d_<FPT2>(x2,y2) );
HOMOG2D_CHECK_IS_NUMBER(FP1);
HOMOG2D_CHECK_IS_NUMBER(FP2);
HOMOG2D_CHECK_IS_NUMBER(FP3);
HOMOG2D_CHECK_IS_NUMBER(FP4);
set( Point2d_<FPT>(x1,y1), Point2d_<FPT>(x2,y2) );
}

/// Translate Segment
Expand Down Expand Up @@ -5396,7 +5417,7 @@ the one with smallest y-coordinate will be returned first
#endif
void draw( img::Image<img::SvgImage>&, img::DrawParams dp=img::DrawParams() ) const;

}; // class Segment_
}; // class SegVec

//------------------------------------------------------------------
template<typename SV,typename FPT>
Expand All @@ -5420,7 +5441,6 @@ SegVec<SV,FPT>::getPointSide( const Point2d_<T>& pt ) const
return out;
}


//------------------------------------------------------------------
/// Returns a segment with same support line but tripled length.
/**
Expand Down

0 comments on commit 6217e09

Please sign in to comment.