diff --git a/modules/core/doc/basic_structures.rst b/modules/core/doc/basic_structures.rst index 886a886df..280c317ae 100644 --- a/modules/core/doc/basic_structures.rst +++ b/modules/core/doc/basic_structures.rst @@ -316,6 +316,7 @@ RotatedRect RotatedRect(); RotatedRect(const Point2f& center, const Size2f& size, float angle); RotatedRect(const CvBox2D& box); + RotatedRect(const Point2f& point1, const Point2f& point2, const Point2f& point3); //! returns 4 vertices of the rectangle void points(Point2f pts[]) const; @@ -338,7 +339,11 @@ The class represents rotated (i.e. not up-right) rectangles on a plane. Each rec :param size: Width and height of the rectangle. :param angle: The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle. :param box: The rotated rectangle parameters as the obsolete CvBox2D structure. + .. ocv:function:: RotatedRect::RotatedRect(const Point2f& point1, const Point2f& point2, const Point2f& point3) + :param point1: + :param point2: + :param point3: Any 3 end points of the RotatedRect. They must be given in order (either clockwise or anticlockwise). .. ocv:function:: void RotatedRect::points( Point2f pts[] ) const .. ocv:function:: Rect RotatedRect::boundingRect() const diff --git a/modules/core/include/opencv2/core/types.hpp b/modules/core/include/opencv2/core/types.hpp index e2b49749e..0b09c6fb0 100644 --- a/modules/core/include/opencv2/core/types.hpp +++ b/modules/core/include/opencv2/core/types.hpp @@ -392,6 +392,7 @@ public: //! various constructors RotatedRect(); RotatedRect(const Point2f& center, const Size2f& size, float angle); + RotatedRect(const Point2f& point1, const Point2f& point2, const Point2f& point3); //! returns 4 vertices of the rectangle void points(Point2f pts[]) const; diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 03b649072..a1d6044d5 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -5204,6 +5204,30 @@ void normalize( const SparseMat& src, SparseMat& dst, double a, int norm_type ) ////////////////////// RotatedRect ////////////////////// +RotatedRect::RotatedRect(const Point2f& _point1, const Point2f& _point2, const Point2f& _point3) +{ + Point2f _center = 0.5f * (_point1 + _point3); + Vec2f vecs[2]; + vecs[0] = Vec2f(_point1 - _point2); + vecs[1] = Vec2f(_point2 - _point3); + // check that given sides are perpendicular + CV_Assert( abs(vecs[0].dot(vecs[1])) / (norm(vecs[0]) * norm(vecs[1])) <= FLT_EPSILON ); + + // wd_i stores which vector (0,1) or (1,2) will make the width + // One of them will definitely have slope within -1 to 1 + int wd_i = 0; + if( abs(vecs[1][1]) < abs(vecs[1][0]) ) wd_i = 1; + int ht_i = (wd_i + 1) % 2; + + float _angle = atan(vecs[wd_i][1] / vecs[wd_i][0]) * 180.0f / (float) CV_PI; + float _width = (float) norm(vecs[wd_i]); + float _height = (float) norm(vecs[ht_i]); + + center = _center; + size = Size2f(_width, _height); + angle = _angle; +} + void RotatedRect::points(Point2f pt[]) const { double _angle = angle*CV_PI/180.; diff --git a/modules/core/test/test_rotatedrect.cpp b/modules/core/test/test_rotatedrect.cpp new file mode 100644 index 000000000..c600ef1dd --- /dev/null +++ b/modules/core/test/test_rotatedrect.cpp @@ -0,0 +1,107 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class Core_RotatedRectConstructorTest : public cvtest::BaseTest +{ +public: + Core_RotatedRectConstructorTest(); +protected: + int prepare_test_case( int ); + void run_func(); + int validate_test_results( int ); + float MAX_COORD_VAL; + Point2f a, b, c; + RotatedRect rec; +}; + +Core_RotatedRectConstructorTest::Core_RotatedRectConstructorTest() +{ + test_case_count = 100; + MAX_COORD_VAL = 1000.0f; +} + +int Core_RotatedRectConstructorTest::prepare_test_case( int test_case_idx ) +{ + cvtest::BaseTest::prepare_test_case( test_case_idx ); + RNG& rng = ts->get_rng(); + a = Point2f( rng.uniform(-MAX_COORD_VAL, MAX_COORD_VAL), rng.uniform(-MAX_COORD_VAL, MAX_COORD_VAL) ); + do + { + b = Point2f( rng.uniform(-MAX_COORD_VAL, MAX_COORD_VAL), rng.uniform(-MAX_COORD_VAL, MAX_COORD_VAL) ); + } + while( norm(a - b) <= FLT_EPSILON ); + Vec2f along(a - b); + Vec2f perp = Vec2f(-along[1], along[0]); + double d = (double) rng.uniform(1.0f, 5.0f); + if( cvtest::randInt(rng) % 2 == 0 ) d = -d; + c = Point2f( (float) ((double) b.x + d * perp[0]), (float) ((double) b.y + d * perp[1]) ); + return 1; +} + +void Core_RotatedRectConstructorTest::run_func() +{ + rec = RotatedRect(a, b, c); +} + +int Core_RotatedRectConstructorTest::validate_test_results( int ) +{ + Point2f vertices[4]; + rec.points(vertices); + int count_match = 0; + for( int i = 0; i < 4; i++ ) + { + if( norm(vertices[i] - a) <= 0.001 ) count_match++; + else if( norm(vertices[i] - b) <= 0.001 ) count_match++; + else if( norm(vertices[i] - c) <= 0.001 ) count_match++; + } + if( count_match == 3 ) + return cvtest::TS::OK; + ts->printf( cvtest::TS::LOG, "RotatedRect end points don't match those supplied in constructor"); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return cvtest::TS::OK; +} + +TEST(Core_RotatedRect, three_point_constructor) { Core_RotatedRectConstructorTest test; test.safe_run(); }