-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathhomog2d.hpp
13098 lines (11553 loc) · 351 KB
/
homog2d.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**************************************************************************
This file is part of the C++ library "homog2d", dedicated to
handle 2D lines and points, see https://github.com/skramm/homog2d
Author & Copyright 2019-2025 Sebastien Kramm
Contact: [email protected]
Licence: MPL v2
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
**************************************************************************/
/**
\file homog2d.hpp
\brief single header file, implements some 2D homogeneous stuff.
See https://github.com/skramm/homog2d
*/
#ifndef HG_HOMOG2D_HPP
#define HG_HOMOG2D_HPP
#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <numeric>
#include <array>
#include <set>
#include <list>
#include <vector>
#include <map>
#include <stack>
#include <iomanip>
#include <cassert>
#include <sstream>
#include <type_traits>
#include <functional>
#include <limits>
#include <cstdint> // required for uint8_t
#include <memory> // required for std::unique_ptr
#ifdef HOMOG2D_USE_SVG_IMPORT
#define HOMOG2D_ENABLE_VRTP
// #include <cctype> // why was that needed in the first place?
#include "tinyxml2.h"
#endif // HOMOG2D_USE_SVG_IMPORT
#ifdef HOMOG2D_ENABLE_VRTP
#include <variant>
#endif
#ifdef HOMOG2D_USE_EIGEN
#include <Eigen/Dense>
#endif
#ifdef HOMOG2D_USE_TTMATH
#include <ttmath/ttmath.h>
#ifndef HOMOG2D_INUMTYPE
#define HOMOG2D_INUMTYPE ttmath::Big<2,2>
#endif
#define homog2d_abs ttmath::Abs
#define homog2d_sin ttmath::Sin
#define homog2d_cos ttmath::Cos
#define homog2d_acos ttmath::ACos
#define homog2d_asin ttmath::ASin
#define homog2d_atan ttmath::ATan
#define homog2d_sqrt ttmath::Sqrt
#else
#define homog2d_abs std::abs
#define homog2d_sin std::sin
#define homog2d_cos std::cos
#define homog2d_acos std::acos
#define homog2d_asin std::asin
#define homog2d_atan std::atan
#define homog2d_sqrt std::sqrt
#endif
#ifdef HOMOG2D_USE_OPENCV
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#endif
#ifdef HOMOG2D_USE_BOOSTGEOM
#include <boost/geometry.hpp>
#endif
#ifdef _MSC_VER
#define HOMOG2D_PRETTY_FUNCTION __FUNCSIG__
#else
#define HOMOG2D_PRETTY_FUNCTION __PRETTY_FUNCTION__
#endif
#ifdef HOMOG2D_DEBUGMODE
#define HOMOG2D_START std::cout << "START: line:" << __LINE__ \
<< " func=\n" << HOMOG2D_PRETTY_FUNCTION << "\n"
// #define HOMOG2D_START std::cout << __FUNCTION__ << "()\n"
#else
#define HOMOG2D_START
#endif
// << std::scientific << std::setprecision(10)
#ifdef HOMOG2D_DEBUGMODE
#define HOMOG2D_LOG(a) \
std::cout << '-' << __FUNCTION__ << "(), line " << __LINE__ << ": " \
<< a << std::endl;
#else
#define HOMOG2D_LOG(a) {;}
#endif
#define HOMOG2D_ASSERT( a ) \
if( !(a) ) \
{ \
std::cerr << "ASSERT FAILURE, line=" << __LINE__ << std::endl; \
std::exit(1); \
}
/// Assert debug macro, used internally if \c HOMOG2D_DEBUGMODE is defined
#define HOMOG2D_DEBUG_ASSERT(a,b) \
{ \
if( (a) == false ) \
{ \
std::cerr << "Homog2d assert failure, version:" << HOMOG2D_VERSION \
<< ", line:" << __LINE__ << "\n -details: " << b << '\n'; \
std::cout << "homog2d: internal failure, please check stderr and report this on https://github.com/skramm/homog2d/issues\n"; \
std::exit(1); \
} \
}
#define HOMOG2D_CHECK_ROW_COL \
if( r > 2 ) \
throw std::runtime_error( "Error: invalid row value: r=" + std::to_string(r) ); \
if( c > 2 ) \
throw std::runtime_error( "Error: invalid col value: r=" + std::to_string(r) )
#ifdef HOMOG2D_USE_TTMATH
# define HOMOG2D_CHECK_IS_NUMBER(T)
#else
# define HOMOG2D_CHECK_IS_NUMBER(T) \
static_assert( (std::is_arithmetic<T>::value && !std::is_same<T, bool>::value), "Type of value must be numerical" )
#endif
#ifndef HOMOG2D_NOWARNINGS
#define HOMOG2D_LOG_WARNING( a ) \
std::cerr << "homog2d warning (" << ++err::warningCount() << "), l. " << __LINE__ << ": " << a << "\n";
#else
#define HOMOG2D_LOG_WARNING
#endif
/*
\todo 20230212 ttmath support: this definition does not work, I don't know why !!! see namespace \ref trait
\verbatim
#define HOMOG2D_CHECK_IS_NUMBER(T) \
static_assert( \
((std::is_arithmetic<T>::value && !std::is_same<T, bool>::value) || trait::IsBigNumType<T>::value), \
"Type of value must be numerical" )
\endverbatim
*/
/// Internal type used for numerical computations, possible values: \c double, <code>long double</code>
#if !defined(HOMOG2D_INUMTYPE)
#define HOMOG2D_INUMTYPE double
#endif
#if !defined(HOMOG2D_BIND_X)
#define HOMOG2D_BIND_X x
#endif
#if !defined(HOMOG2D_BIND_Y)
#define HOMOG2D_BIND_Y y
#endif
/// Error throw wrapper macro
#define HOMOG2D_THROW_ERROR_1( msg ) \
{ \
std::ostringstream oss; \
oss << "homog2d: line " << __LINE__ << ", function:" << __FUNCTION__ << "(): " \
<< msg << "\n -full function name: " << HOMOG2D_PRETTY_FUNCTION \
<< "\n -Error count=" << ++err::errorCount(); \
throw std::runtime_error( oss.str() ); \
}
/// Error throw wrapper macro, first arg is the function name
#define HOMOG2D_THROW_ERROR_2( func, msg ) \
{ \
std::ostringstream oss; \
oss << "homog2d: line " << __LINE__ << ", function:" << func << "(): " \
<< msg << "\n -full function name: " << HOMOG2D_PRETTY_FUNCTION \
<< "\n -Error count=" << ++err::errorCount(); \
throw std::runtime_error( oss.str() ); \
}
///////////////////////////////////////
// Default values for thresholds
#ifndef HOMOG2D_THR_ZERO_DIST
#define HOMOG2D_THR_ZERO_DIST 1E-10
#endif
#ifndef HOMOG2D_THR_ZERO_ORTHO_DIST
#define HOMOG2D_THR_ZERO_ORTHO_DIST 1E-14
#endif
// default value: 1 thousand of a radian (tan = 0.001 too)
#ifndef HOMOG2D_THR_ZERO_ANGLE
#define HOMOG2D_THR_ZERO_ANGLE 0.001
#endif
#ifndef HOMOG2D_THR_ZERO_DENOM
#define HOMOG2D_THR_ZERO_DENOM 1E-10
#endif
#ifndef HOMOG2D_THR_ZERO_DETER
#define HOMOG2D_THR_ZERO_DETER 1E-15
#endif
///////////////////////////////////////
/// Max number of iterations for "Point inside Polygon" algorithm.
/// May be adjusted, see manual
#ifndef HOMOG2D_MAXITER_PIP
#define HOMOG2D_MAXITER_PIP 5
#endif
#define HOMOG2D_VERSION "2.12.1"
// some MS environments seem to lack Pi definition, even if _USE_MATH_DEFINES is defined
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
namespace h2d {
/// Holds static counters, for runtime errors and warnings
namespace err {
/// Used to count the errors
/**
This is used in the HOMOG2D_THROW_ERROR_1 macros. Some user code could catch the exceptions, thus
this will enable the counting of errors
\todo 20250123: for some reason, the error count is always 42! Need to investigate this.
*/
inline size_t& errorCount()
{
static size_t c;
return c;
}
/// Used in macro HOMOG2D_LOG_WARNING
inline size_t& warningCount()
{
static size_t c;
return c;
}
} //namespace err
/// Holds the types needed for policy based design
namespace typ {
/// Used to determine if line or point, see base::LPBase
struct IsLine {};
struct IsPoint {};
struct IsHomogr {};
struct IsEpipmat {};
/// Used to determine the type of "point pair (segment of vector), see base::SegVec
struct IsSegment {};
/// \sa IsSegment
struct IsOSeg {};
/// Used to determine the type of polyline (\ref CPolyline_ or \ref OPolyline_), see base::PolylineBase
struct IsClosed {};
/// \sa IsClosed
struct IsOpen {};
/// \name These are used as static member type SType
///@{
struct T_Point {};
struct T_Line {};
struct T_Circle {};
struct T_FRect {};
struct T_Segment {};
struct T_OSeg {};
struct T_OPol {};
struct T_CPol {};
struct T_Ellipse {};
///@}
} // namespace typ
namespace detail {
template<typename FPT> class Matrix_;
/// Helper class for Root (Point/Line) type, used as a trick to allow partial specialization of member functions
template<typename> struct BaseHelper {};
/// Helper class for used to get the underlying floating-point type, see Dtype and Common::dtype()
template<typename> struct DataFpType {};
/// Helper class for PolylineBase, used as a trick to allow partial specialization of member functions
template<typename> struct PlHelper {};
#ifdef HOMOG2D_FUTURE_STUFF
/// Helper class for Matrix type
template<typename T1>
struct HelperMat {};
template<>
struct HelperMat<typ::IsHomogr>
{
using M_OtherType = IsEpipmat;
};
template<>
struct HelperMat<typ::IsEpipmat>
{
using M_OtherType = IsHomogr;
};
#endif
template<typename> struct HelperPL;
template<>
struct HelperPL<typ::IsPoint>
{
using OtherType = typ::IsLine;
};
template<>
struct HelperPL<typ::IsLine>
{
using OtherType = typ::IsPoint;
};
/// A trick used in static_assert, so it aborts only if function is instanciated
template<typename T>
struct AlwaysFalse {
enum { value = false };
};
} // namespace detail
/// Holds base classes, not part of API
namespace base {
template<typename PLT,typename FPT> class PolylineBase;
template<typename LP, typename FPT> class LPBase;
template<typename SV, typename FPT> class SegVec;
}
template<typename LP,typename FPT> class Hmatrix_;
template<typename T>
using Homogr_ = Hmatrix_<typ::IsHomogr,T>;
#ifdef HOMOG2D_FUTURE_STUFF
template<typename T>
using Epipmat_ = Hmatrix_<typ::IsEpipmat,T>;
#endif
template<typename FPT> class Circle_;
template<typename FPT> class FRect_;
template<typename FPT> class Ellipse_;
namespace img {
struct SvgImage; // forward declaration
}
template<typename T>
using Point2d_ = base::LPBase<typ::IsPoint,T>;
template<typename T>
using Line2d_ = base::LPBase<typ::IsLine,T>;
template<typename T>
using Segment_ = base::SegVec<typ::IsSegment,T>;
template<typename T>
using OSegment_ = base::SegVec<typ::IsOSeg,T>;
template<typename T1,typename T2>
using PointPair2_ = std::pair<Point2d_<T1>,Point2d_<T2>>;
template<typename T>
using PointPair_ = std::pair<Point2d_<T>,Point2d_<T>>;
template<typename T>
using CPolyline_ = base::PolylineBase<typ::IsClosed,T>;
template<typename T>
using OPolyline_ = base::PolylineBase<typ::IsOpen,T>;
#ifdef HOMOG2D_ENABLE_VRTP
/// A variant type, holding all possible types. Used to achieve runtime polymorphism
/**
See https://github.com/skramm/homog2d/blob/master/docs/homog2d_manual.md#section_rtp
*/
template<typename FPT>
using CommonType_ = std::variant<
Segment_<FPT>,
OSegment_<FPT>,
Point2d_<FPT>,
Line2d_<FPT>,
Circle_<FPT>,
Ellipse_<FPT>,
FRect_<FPT>,
CPolyline_<FPT>,
OPolyline_<FPT>
>;
#endif // HOMOG2D_ENABLE_VRTP
//------------------------------------------------------------------
/// Holds drawing related code, independent of back-end library
namespace img {
/// Color type , see DrawParams
struct Color
{
uint8_t r = 80;
uint8_t g = 80;
uint8_t b = 80;
Color( uint8_t rr, uint8_t gg, uint8_t bb ): r(rr),g(gg),b(bb) {}
Color() = default;
friend std::ostream& operator << ( std::ostream& f, const Color& c )
{
f << "Color:" << (int)c.r << '-' << (int)c.g << '-' << (int)c.b;
return f;
}
};
/// Helper function, will generate a vector of \c nb random RGB colors
/**
- RGB values will be between \c minval and \c minval+coeff
*/
inline
std::vector<img::Color>
genRandomColors( size_t nb, int minval=20, int maxval=250 )
{
if( maxval<=minval )
HOMOG2D_THROW_ERROR_1( "Illegal values for minval and maxval" );
std::vector<img::Color> vcol( nb );
std::srand( std::time(nullptr) );
for( size_t i=0; i<nb; i++ )
{
auto colR = 1.0*std::rand() / RAND_MAX * (maxval-minval) + minval;
auto colG = 1.0*std::rand() / RAND_MAX * (maxval-minval) + minval;
auto colB = 1.0*std::rand() / RAND_MAX * (maxval-minval) + minval;
vcol[i] = img::Color(colR,colG,colB);
}
return vcol;
}
/// A svg image as a wrapper around a string, see manual, "Drawing things" section
struct SvgImage
{
std::ostringstream _svgString; ///< the svg objects
};
//------------------------------------------------------------------
/// Point drawing style, see DrawParams
/**
Demo: https://github.com/skramm/homog2d/blob/master/docs/homog2d_manual.md#drawing_params
\warning Check nextPointStyle() in case of added values here!
*/
enum class PtStyle: uint8_t
{
Plus, ///< \c + symbol
Times, ///< \c X symbol
Star, ///< \c * symbol
Diam, ///< diamond
Squ, ///< square (new 20241101 !)
Dot ///< dot (circle)
};
inline
const char*
getString( PtStyle t )
{
const char* s=0;
switch( t )
{
case PtStyle::Plus: s="Plus"; break;
case PtStyle::Times: s="Times"; break;
case PtStyle::Star: s="Star"; break;
case PtStyle::Diam: s="Diam"; break;
case PtStyle::Squ: s="Square";break;
case PtStyle::Dot: s="Dot"; break; // WARNING: keep this as last one (assumed to be last one in some code)
default: assert(0);
}
return s;
}
//------------------------------------------------------------------
/// Draw parameters, independent of back-end library
class DrawParams
{
template<typename T> friend class h2d::Circle_;
template<typename T> friend class h2d::FRect_;
template<typename T> friend class h2d::Ellipse_;
template<typename T,typename U> friend class h2d::base::PolylineBase;
template<typename T,typename U> friend class h2d::base::LPBase;
template<typename T,typename U> friend class h2d::base::SegVec;
/// Inner struct, holds the values. Needed so we can assign a default value as static member
/// \todo 20240329 maybe we can merge parameters _ptDelta and _pointSize into a single one?
struct Dp_values
{
Color _color;
int _lineThickness = 1;
int _pointSize = 4;
int _lineType = 1; /// if OpenCv: 1 for cv::LINE_AA, 2 for cv::LINE_8
uint8_t _ptDelta = 5; ///< pixels, used for drawing points
PtStyle _ptStyle = PtStyle::Plus;
bool _enhancePoint = false; ///< to draw selected points
bool _showPoints = false; ///< show the points (useful only for Segment_ and Polyline_)
bool _showIndex = false; ///< show the index as number
int _fontSize = 20; ///< font size for drawText()
std::string _attrString; ///< added attributes (SVG only)
/// Returns the point style following the current one
PtStyle nextPointStyle() const
{
if( _ptStyle == PtStyle::Dot )
return PtStyle::Plus;
auto curr = static_cast<int>(_ptStyle);
return static_cast<PtStyle>(curr+1);
}
};
friend std::ostream& operator << ( std::ostream& f, const DrawParams& dp )
{
f << "-" << dp._dpValues._color
<< "\n-line width=" << dp._dpValues._lineThickness
<< "\n-pointSize=" << dp._dpValues._pointSize
<< "\n-showPoints=" << dp._dpValues._showPoints
<< "\n-fontSize=" << dp._dpValues._fontSize
<< '\n';
return f;
}
public:
Dp_values _dpValues;
private:
static Dp_values& p_getDefault()
{
static Dp_values s_defValue;
return s_defValue;
}
public:
DrawParams()
{
_dpValues = p_getDefault();
}
void setDefault()
{
p_getDefault() = this->_dpValues;
}
static void resetDefault()
{
p_getDefault() = Dp_values();
}
DrawParams& setPointStyle( PtStyle ps )
{
if( (int)ps > (int)PtStyle::Dot )
throw std::runtime_error( "Error: invalid value for point style");
_dpValues._ptStyle = ps;
return *this;
}
DrawParams& setPointSize( uint8_t ps )
{
if( ps%2 == 0 )
HOMOG2D_THROW_ERROR_1( "odd number required" );
_dpValues._pointSize = ps;
_dpValues._ptDelta = ps;
return *this;
}
DrawParams& setThickness( uint8_t t )
{
_dpValues._lineThickness = t;
return *this;
}
DrawParams& setColor( uint8_t r, uint8_t g, uint8_t b )
{
_dpValues._color = Color{r,g,b};
return *this;
}
DrawParams& setColor( Color col )
{
_dpValues._color = col;
return *this;
}
DrawParams& selectPoint()
{
_dpValues._enhancePoint = true;
return *this;
}
/// Set or unset the drawing of points (useful only for Segment_ and Polyline_)
DrawParams& showPoints( bool b=true )
{
_dpValues._showPoints = b;
return *this;
}
/// Set font size for drawText()
DrawParams& setFontSize( int value /* pixels */ )
{
assert( value > 1 );
_dpValues._fontSize = value;
return *this;
}
/// Set or unset the drawing of points (useful only for Segment_ and Polyline_)
DrawParams& showIndex( bool b=true )
{
_dpValues._showIndex = b;
return *this;
}
/// Add some specific SVG attributes (ignored for Opencv renderings)
/** \sa getAttrString() */
DrawParams& setAttrString( std::string attr )
{
_dpValues._attrString = attr;
return *this;
}
Color color() const
{
return _dpValues._color;
}
#ifdef HOMOG2D_USE_OPENCV
cv::Scalar cvColor() const
{
return cv::Scalar( _dpValues._color.b, _dpValues._color.g, _dpValues._color.r );
}
#endif // HOMOG2D_USE_OPENCV
private:
/// Checks if the user-given SVG attribute string (with \ref setAttrString() ) holds the fill="none" mention.
/**
This is because to have no filling, the object needs to have the fill="none" attribute, so the default
behavior is to always add that attribute.<br>
But then if the user wants some filling, then we would have both fill="none" and fill="somecolor",
and that would render the svg invalid.<br>
So the drawing code checks if user has added some filling, and if so, does not add the fill="none" attribute.
*/
bool holdsFill() const
{
if( !_dpValues._attrString.empty() )
if( _dpValues._attrString.find("fill=") != std::string::npos )
return true;
return false;
}
/// \sa setAttrString()
std::string getAttrString() const
{
if( _dpValues._attrString.empty() )
return std::string();
return _dpValues._attrString + ' ';
}
std::string getSvgRgbColor() const
{
std::ostringstream oss;
oss << "rgb("
<< (int)_dpValues._color.r << ','
<< (int)_dpValues._color.g << ','
<< (int)_dpValues._color.b
<< ')';
return oss.str();
}
}; // class DrawParams
//------------------------------------------------------------------
/// Opaque data structure, will hold the image type, depending on back-end library.
/// This type is the one used in all the drawing functions.
/**
At present the two allowed types are cv::Mat
(external Opencv library, requires the symbol HOMOG2D_USE_OPENCV to be defined)
or SvgImage (no dependency)
*/
template<typename T>
class Image
{
// template<typename U>
friend std::ostream& operator << ( std::ostream&, const Image<SvgImage>& );
private:
T _realImg;
size_t _width = 500;
size_t _height = 500;
public:
Image() = default;
Image( T& m ): _realImg(m)
{}
/// Returns a reference on the underlying image
T& getReal()
{
return _realImg;
}
/// Returns a const reference on the underlying image
const T& getReal() const
{
return _realImg;
}
std::pair<size_t,size_t> size() const
{
return std::make_pair( _width, _height );
}
/// That constructor is the default, shouln't be instanciated, see specializations
Image( size_t, size_t )
{
assert(0);
// static_assert( detail::AlwaysFalse<std::false_type>::value, "no concrete implementation available" );
// static_assert( std::false_type, "no concrete implementation available" );
}
void setSize( size_t width, size_t height );
template<typename F>
void setSize( const std::pair<F,F>& );
void write( std::string ) const // will be specialized
{
assert(0);
}
int cols() const { return _width; }
int rows() const { return _height; }
void clear( Color c=Color(255,255,255) ) { clear(c.r,c.g,c.b); }
void clear( uint8_t, uint8_t, uint8_t )
{
assert(0);
}
void clear( uint8_t )
{
assert(0);
}
void drawText( std::string, Point2d_<float>, img::DrawParams dp=img::DrawParams() );
template<typename U>
void draw( const U& object, img::DrawParams dp=img::DrawParams() );
template<typename U,typename V>
void draw( const std::pair<U,V>& p_objects, img::DrawParams dp=img::DrawParams() );
#ifdef HOMOG2D_USE_OPENCV
/// Show image on window \c wname (not available for SVG !)
void show( std::string wname )
{
cv::imshow( wname, _realImg );
}
private:
void p_setSize( size_t width, size_t height )
{
_width = width;
_height = height;
_realImg.create( (int)height, (int)width, CV_8UC3 );
clear();
}
#endif
}; // class Image
#ifdef HOMOG2D_USE_OPENCV
template <>
inline
Image<cv::Mat>::Image( size_t width, size_t height )
{
p_setSize( width, height );
}
template <>
inline
void
Image<cv::Mat>::setSize( size_t width, size_t height )
{
p_setSize( width, height );
}
#endif
template <typename IMG>
void
Image<IMG>::setSize( size_t width, size_t height )
{
_width = width;
_height = height;
}
template <typename IMG>
template <typename T>
void
Image<IMG>::setSize( const std::pair<T,T>& pa )
{
setSize( pa.first, pa.second );
}
template <>
inline
Image<SvgImage>::Image( size_t width, size_t height )
{
setSize( width, height );
}
template <>
inline
void
Image<SvgImage>::write( std::string fname ) const
{
std::ofstream file( fname );
if( !file.is_open() )
{
HOMOG2D_THROW_ERROR_1( "unable to open output file '" + fname + "'" );
}
file << "<svg version=\"1.1\" width=\"" << _width
<< "\" height=\"" << _height
<< "\" style=\"background-color:white;\" xmlns=\"http://www.w3.org/2000/svg\">\n"
<< "<style>\n"
<< ".txt1 { font: bold 12px sans-serif; };\n" // text style, you can change or add classes as required
<< "</style>\n";
file << _realImg._svgString.str();
file << "</svg>\n";
}
template <>
inline
void
Image<SvgImage>::clear( uint8_t, uint8_t, uint8_t )
{
_realImg._svgString.str("");
_realImg._svgString.clear();
}
#ifdef HOMOG2D_USE_OPENCV
template <>
inline
void
Image<cv::Mat>::clear( uint8_t r, uint8_t g, uint8_t b )
{
_realImg = cv::Scalar(b,g,r);
}
template <>
inline
void
Image<cv::Mat>::clear( uint8_t col )
{
_realImg = cv::Scalar(col,col,col);
}
template <>
inline
void
Image<cv::Mat>::write( std::string fname ) const
{
cv::imwrite( fname, _realImg );
}
#endif // HOMOG2D_USE_OPENCV
template<typename IMG>
template<typename U>
void Image<IMG>::draw( const U& object, img::DrawParams dp )
{
object.draw( *this, dp );
}
template<typename IMG>
template<typename U,typename V>
void Image<IMG>::draw( const std::pair<U,V>& pairp, img::DrawParams dp )
{
pairp.first.draw( *this, dp );
pairp.second.draw( *this, dp );
}
} // namespace img
/////////////////////////////////////////////////////////////////////////////
// SECTION - PUBLIC ENUM DECLARATIONS
/////////////////////////////////////////////////////////////////////////////
/// Used in base::PolylineBase_::rotate() member function
enum class Rotate: int8_t
{
CCW, ///< Counter ClockWise rotation
CW, ///< ClockWise rotation
Full, ///< 180° rotation
VMirror, ///< vertical symmetry
HMirror ///< horizontal symmetry
};
enum class CardDir: int8_t { Bottom,Top, Left, Right };
/// Used in Line2d::getValue() and getOrthogonalLine()
enum class GivenCoord: uint8_t { X, Y };
/// Used in line constructor, to instanciate a H or V line, see base::LPBase( LineDir, T )
enum class LineDir: uint8_t { H, V };
/// Type of Root object, see rtp::Root::type().
/// Maybe printed out with getString()
/// \sa type()
enum class Type: uint8_t { Line2d, Point2d, Segment, OSegment, FRect, Circle, Ellipse, OPolyline, CPolyline };
/// Type of underlying floating point, see LPBase::dtype().
/// Maybe printed out with getString()
enum class Dtype: uint8_t {
Float, Double, LongDouble,
Other, // ?
#ifdef HOMOG2D_USE_TTMATH
Ttmath ///< only if HOMOG2D_USE_TTMATH is defined, see manual
#endif
};
/// Returns stringified version of \ref type()
inline
const char* getString( Type t )
{
const char* s=0;
switch( t )
{
case Type::Line2d: s="Line2d"; break;
case Type::Point2d: s="Point2d"; break;
case Type::Segment: s="Segment"; break;
case Type::OSegment: s="OSegment"; break;
case Type::FRect: s="FRect"; break;
case Type::Circle: s="Circle"; break;
case Type::Ellipse: s="Ellipse"; break;
case Type::OPolyline: s="OPolyline"; break;
case Type::CPolyline: s="CPolyline"; break;
assert(0);
}
return s;
}
#ifdef HOMOG2D_ENABLE_VRTP
//------------------------------------------------------------------
/// Holds functors, used to manage runtime polymorphism using \c std::variant.
/// See https://github.com/skramm/homog2d/blob/master/docs/homog2d_manual.md#section_rtp
namespace fct {
//------------------------------------------------------------------
/// A functor to get the type of an object in a std::variant, call with std::visit()
/**
\sa CommonType_
\sa type()
*/
struct TypeFunct
{
template<typename T>
Type operator ()(const T& a)
{
return a.type();
}
};
struct DTypeFunct
{
template<typename T>
Dtype operator ()(const T& a)
{
return a.dtype();
}
};
//------------------------------------------------------------------
/// A functor to get the length of an object in a std::variant, call with std::visit()
/**
\sa CommonType_
\sa length()
*/
struct LengthFunct
{
template<typename T>
HOMOG2D_INUMTYPE operator ()(const T& a)
{
return a.length();
}
};
//------------------------------------------------------------------
/// A functor to get the area of an object in a std::variant, call with std::visit()
/**
\sa CommonType_
\sa area()