You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
5.3 KiB

// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2024 Intel Corporation. All Rights Reserved.
#pragma once
#include "float2.h"
#include <algorithm> // max,min
#include <cmath> // floor
namespace rs2 {
template < typename T > T normalizeT( const T & in_val, const T & min, const T & max )
{
if( min >= max )
return 0;
return ( ( in_val - min ) / ( max - min ) );
}
template < typename T > T unnormalizeT( const T & in_val, const T & min, const T & max )
{
if( min == max )
return min;
return ( ( in_val * ( max - min ) ) + min );
}
struct rect
{
float x, y;
float w, h;
void operator=( const rect & other )
{
x = other.x;
y = other.y;
w = other.w;
h = other.h;
}
operator bool() const { return w * w > 0 && h * h > 0; }
bool operator==( const rect & other ) const { return x == other.x && y == other.y && w == other.w && h == other.h; }
bool operator!=( const rect & other ) const { return ! ( *this == other ); }
rect normalize( const rect & normalize_to ) const
{
return rect{ normalizeT( x, normalize_to.x, normalize_to.x + normalize_to.w ),
normalizeT( y, normalize_to.y, normalize_to.y + normalize_to.h ),
normalizeT( w, 0.f, normalize_to.w ),
normalizeT( h, 0.f, normalize_to.h ) };
}
rect unnormalize( const rect & unnormalize_to ) const
{
return rect{ unnormalizeT( x, unnormalize_to.x, unnormalize_to.x + unnormalize_to.w ),
unnormalizeT( y, unnormalize_to.y, unnormalize_to.y + unnormalize_to.h ),
unnormalizeT( w, 0.f, unnormalize_to.w ),
unnormalizeT( h, 0.f, unnormalize_to.h ) };
}
// Calculate the intersection between two rects
// If the intersection is empty, a rect with width and height zero will be returned
rect intersection( const rect & other ) const
{
auto x1 = std::max( x, other.x );
auto y1 = std::max( y, other.y );
auto x2 = std::min( x + w, other.x + other.w );
auto y2 = std::min( y + h, other.y + other.h );
return { x1, y1, std::max( x2 - x1, 0.f ), std::max( y2 - y1, 0.f ) };
}
// Calculate the area of the rect
float area() const { return w * h; }
rect cut_by( const rect & r ) const
{
auto x1 = x;
auto y1 = y;
auto x2 = x + w;
auto y2 = y + h;
x1 = std::max( x1, r.x );
x1 = std::min( x1, r.x + r.w );
y1 = std::max( y1, r.y );
y1 = std::min( y1, r.y + r.h );
x2 = std::max( x2, r.x );
x2 = std::min( x2, r.x + r.w );
y2 = std::max( y2, r.y );
y2 = std::min( y2, r.y + r.h );
return { x1, y1, x2 - x1, y2 - y1 };
}
bool contains( const float2 & p ) const
{
return ( p.x >= x ) && ( p.x < x + w ) && ( p.y >= y ) && ( p.y < y + h );
}
rect pan( const float2 & p ) const { return { x - p.x, y - p.y, w, h }; }
rect center() const { return { x + w / 2.f, y + h / 2.f, 0, 0 }; }
rect adjust_ratio( float2 size ) const
{
auto H = static_cast< float >( h ), W = static_cast< float >( h ) * size.x / size.y;
if( W > w )
{
auto scale = w / W;
W *= scale;
H *= scale;
}
return { float( floor( x + floor( w - W ) / 2 ) ), float( floor( y + floor( h - H ) / 2 ) ), W, H };
}
rect scale( float factor ) const { return { x, y, w * factor, h * factor }; }
rect grow( int pixels ) const { return { x - pixels, y - pixels, w + pixels * 2, h + pixels * 2 }; }
rect grow( int dx, int dy ) const { return { x - dx, y - dy, w + dx * 2, h + dy * 2 }; }
rect shrink_by( float2 pixels ) const { return { x + pixels.x, y + pixels.y, w - pixels.x * 2, h - pixels.y * 2 }; }
rect center_at( const float2 & new_center ) const
{
auto c = center();
auto diff_x = new_center.x - c.x;
auto diff_y = new_center.y - c.y;
return { x + diff_x, y + diff_y, w, h };
}
rect fit( rect r ) const
{
float new_w = w;
float new_h = h;
if( w < r.w )
new_w = r.w;
if( h < r.h )
new_h = r.h;
auto res = rect{ x, y, new_w, new_h };
return res.adjust_ratio( { w, h } );
}
rect zoom( float zoom_factor ) const
{
auto c = center();
return scale( zoom_factor ).center_at( { c.x, c.y } );
}
rect enclose_in( rect in_rect ) const
{
rect out_rect{ x, y, w, h };
if( w > in_rect.w || h > in_rect.h )
{
return in_rect;
}
if( x < in_rect.x )
{
out_rect.x = in_rect.x;
}
if( y < in_rect.y )
{
out_rect.y = in_rect.y;
}
if( x + w > in_rect.x + in_rect.w )
{
out_rect.x = in_rect.x + in_rect.w - w;
}
if( y + h > in_rect.y + in_rect.h )
{
out_rect.y = in_rect.y + in_rect.h - h;
}
return out_rect;
}
bool intersects( const rect & other ) const
{
return other.contains( { x, y } ) || other.contains( { x + w, y } ) || other.contains( { x, y + h } )
|| other.contains( { x + w, y + h } ) || contains( { other.x, other.y } );
}
};
} // namespace rs2