KiCad PCB EDA Suite
Loading...
Searching...
No Matches
box2.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * Copyright (C) 2013 CERN
7 * @author Tomasz Wlostowski <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifndef __BOX2_H
24#define __BOX2_H
25
26#include <algorithm>
27#include <cmath>
28#include <limits>
29#include <optional>
30
31#include <math/vector2d.h>
32#include <geometry/eda_angle.h>
33#include <core/kicad_algo.h>
34#include <trigo.h>
35
39template <class Vec>
40class BOX2
41{
42public:
43 typedef typename Vec::coord_type coord_type;
44 typedef typename Vec::extended_type size_type;
45 typedef typename Vec::extended_type ecoord_type;
47 typedef std::numeric_limits<coord_type> coord_limits;
48
49 constexpr BOX2() :
50 m_Pos( 0, 0 ),
51 m_Size( 0, 0 ),
52 m_init( false )
53 {};
54
55 constexpr BOX2( const Vec& aPos, const SizeVec& aSize = SizeVec(0, 0) ) :
56 m_Pos( aPos ),
57 m_Size( aSize ),
58 m_init( true )
59 {
60 // Range check
63
64 Normalize();
65 }
66
67 static constexpr BOX2<Vec> ByCorners( const Vec& aCorner1, const Vec& aCorner2 )
68 {
69 return BOX2( aCorner1, aCorner2 - aCorner1 );
70 }
71
72 static constexpr BOX2<Vec> ByCenter( const Vec& aCenter, const SizeVec& aSize )
73 {
74 return BOX2( aCenter - aSize / 2, aSize );
75 }
76
77 constexpr void SetMaximum()
78 {
79 if constexpr( std::is_floating_point<coord_type>() )
80 {
81 m_Pos.x = m_Pos.y = coord_limits::lowest() / 2.0;
82 m_Size.x = m_Size.y = coord_limits::max();
83 }
84 else
85 {
86 // We want to be able to invert the box, so don't use lowest()
87 m_Pos.x = m_Pos.y = -coord_limits::max();
88 m_Size.x = m_Size.y = size_type( coord_limits::max() ) + coord_limits::max();
89 }
90
91 m_init = true;
92 }
93
94 constexpr Vec Centre() const
95 {
98 }
99
105 template <class Container>
106 void Compute( const Container& aPointList )
107 {
108 Vec vmin, vmax;
109
110 typename Container::const_iterator i;
111
112 if( !aPointList.size() )
113 return;
114
115 vmin = vmax = aPointList[0];
116
117 for( i = aPointList.begin(); i != aPointList.end(); ++i )
118 {
119 Vec p( *i );
120 vmin.x = std::min( vmin.x, p.x );
121 vmin.y = std::min( vmin.y, p.y );
122 vmax.x = std::max( vmax.x, p.x );
123 vmax.y = std::max( vmax.y, p.y );
124 }
125
126 SetOrigin( vmin );
127 SetSize( vmax - vmin );
128 }
129
135 constexpr void Move( const Vec& aMoveVector )
136 {
137 m_Pos += aMoveVector;
138 }
139
143 constexpr BOX2<Vec>& Normalize()
144 {
145 if( m_Size.y < 0 )
146 {
147 m_Size.y = -m_Size.y;
149 }
150
151 if( m_Size.x < 0 )
152 {
153 m_Size.x = -m_Size.x;
155 }
156
157 return *this;
158 }
159
165 constexpr bool Contains( const Vec& aPoint ) const
166 {
167 Vec rel_pos = aPoint - m_Pos;
168 Vec size = m_Size;
169
170 if( size.x < 0 )
171 {
172 size.x = -size.x;
173 rel_pos.x += size.x;
174 }
175
176 if( size.y < 0 )
177 {
178 size.y = -size.y;
179 rel_pos.y += size.y;
180 }
181
182 return ( rel_pos.x >= 0 ) && ( rel_pos.y >= 0 ) && ( rel_pos.y <= size.y) &&
183 ( rel_pos.x <= size.x);
184 }
185
191 constexpr bool Contains( coord_type x, coord_type y ) const { return Contains( Vec( x, y ) ); }
192
198 constexpr bool Contains( const BOX2<Vec>& aRect ) const
199 {
200 return Contains( aRect.GetOrigin() ) && Contains( aRect.GetEnd() );
201 }
202
203 constexpr const SizeVec& GetSize() const { return m_Size; }
204 constexpr coord_type GetX() const { return m_Pos.x; }
205 constexpr coord_type GetY() const { return m_Pos.y; }
206
207 constexpr const Vec& GetOrigin() const { return m_Pos; }
208 constexpr const Vec& GetPosition() const { return m_Pos; }
209 constexpr const Vec GetEnd() const { return Vec( GetRight(), GetBottom() ); }
210
211 constexpr size_type GetWidth() const { return m_Size.x; }
212 constexpr size_type GetHeight() const { return m_Size.y; }
213
214 constexpr coord_type GetRight() const
215 {
217 }
218
219 constexpr coord_type GetBottom() const
220 {
222 }
223
224 // Compatibility aliases
225 constexpr coord_type GetLeft() const { return GetX(); }
226 constexpr coord_type GetTop() const { return GetY(); }
227 constexpr const Vec GetCenter() const { return Centre(); }
228
232 constexpr int GetSizeMax() const { return ( m_Size.x > m_Size.y ) ? m_Size.x : m_Size.y; }
233
234 constexpr void SetOrigin( const Vec& pos )
235 {
236 m_Pos = pos;
237 m_init = true;
238 }
239
240 constexpr void SetOrigin( coord_type x, coord_type y )
241 {
242 SetOrigin( Vec( x, y ) );
243 }
244
245 constexpr void SetSize( const SizeVec& size )
246 {
247 m_Size = size;
248 m_init = true;
249 }
250
251 constexpr void SetSize( size_type w, size_type h )
252 {
253 SetSize( SizeVec( w, h ) );
254 }
255
256 constexpr void Offset( coord_type dx, coord_type dy )
257 {
258 m_Pos.x += dx;
259 m_Pos.y += dy;
260 }
261
262 constexpr void Offset( const Vec& offset )
263 {
264 Offset( offset.x, offset.y );
265 }
266
267 constexpr BOX2<Vec> GetWithOffset( const Vec& aMoveVector ) const
268 {
269 BOX2<Vec> ret( *this );
270 ret.Move( aMoveVector );
271 return ret;
272 }
273
274 constexpr void SetX( coord_type val )
275 {
276 SetOrigin( val, m_Pos.y );
277 }
278
279 constexpr void SetY( coord_type val )
280 {
281 SetOrigin( m_Pos.x, val );
282 }
283
284 constexpr void SetWidth( size_type val )
285 {
286 SetSize( val, m_Size.y );
287 }
288
289 constexpr void SetHeight( size_type val )
290 {
291 SetSize( m_Size.x, val );
292 }
293
294 constexpr void SetEnd( coord_type x, coord_type y )
295 {
296 SetEnd( Vec( x, y ) );
297 }
298
299 constexpr void SetEnd( const Vec& pos )
300 {
301 SetSize( SizeVec( pos ) - m_Pos );
302 }
303
308 constexpr bool Intersects( const BOX2<Vec>& aRect ) const
309 {
310 // this logic taken from wxWidgets' geometry.cpp file:
311 bool rc;
312
313 BOX2<Vec> me( *this );
314 BOX2<Vec> rect( aRect );
315 me.Normalize(); // ensure size is >= 0
316 rect.Normalize(); // ensure size is >= 0
317
318 // calculate the left common area coordinate:
319 ecoord_type left = std::max( me.m_Pos.x, rect.m_Pos.x );
320
321 // calculate the right common area coordinate:
322 ecoord_type right = std::min( ecoord_type( me.m_Pos.x ) + me.m_Size.x,
323 ecoord_type( rect.m_Pos.x ) + rect.m_Size.x );
324
325 // calculate the upper common area coordinate:
326 ecoord_type top = std::max( me.m_Pos.y, rect.m_Pos.y );
327
328 // calculate the lower common area coordinate:
329 ecoord_type bottom = std::min( ecoord_type( me.m_Pos.y ) + me.m_Size.y,
330 ecoord_type( rect.m_Pos.y ) + rect.m_Size.y );
331
332 // if a common area exists, it must have a positive (null accepted) size
333 if( left <= right && top <= bottom )
334 rc = true;
335 else
336 rc = false;
337
338 return rc;
339 }
340
344 constexpr BOX2<Vec> Intersect( const BOX2<Vec>& aRect )
345 {
346 BOX2<Vec> me( *this );
347 BOX2<Vec> rect( aRect );
348 me.Normalize(); // ensure size is >= 0
349 rect.Normalize(); // ensure size is >= 0
350
351 Vec topLeft, bottomRight;
352
353 topLeft.x = std::max( me.m_Pos.x, rect.m_Pos.x );
354
355 bottomRight.x = std::min( me.GetRight(), rect.GetRight() );
356
357 topLeft.y = std::max( me.m_Pos.y, rect.m_Pos.y );
358
359 bottomRight.y = std::min( me.GetBottom(), rect.GetBottom() );
360
361 if( topLeft.x < bottomRight.x && topLeft.y < bottomRight.y )
362 return BOX2<Vec>( topLeft, SizeVec( bottomRight ) - topLeft );
363 else
364 return BOX2<Vec>( Vec( 0, 0 ), SizeVec( 0, 0 ) );
365 }
366
370 bool Intersects( const Vec& aPoint1, const Vec& aPoint2 ) const
371 {
372 Vec point2, point4;
373
374 if( Contains( aPoint1 ) || Contains( aPoint2 ) )
375 return true;
376
377 point2.x = GetEnd().x;
378 point2.y = GetOrigin().y;
379 point4.x = GetOrigin().x;
380 point4.y = GetEnd().y;
381
382 //Only need to test 3 sides since a straight line can't enter and exit on same side
383 if( SegmentIntersectsSegment( aPoint1, aPoint2, GetOrigin(), point2 ) )
384 return true;
385
386 if( SegmentIntersectsSegment( aPoint1, aPoint2, point2, GetEnd() ) )
387 return true;
388
389 if( SegmentIntersectsSegment( aPoint1, aPoint2, GetEnd(), point4 ) )
390 return true;
391
392 return false;
393 }
394
399 bool Intersects( const BOX2<Vec>& aRect, const EDA_ANGLE& aRotation ) const
400 {
401 if( !m_init )
402 return false;
403
404 EDA_ANGLE rotation = aRotation;
405 rotation.Normalize();
406
407 /*
408 * Most rectangles will be axis aligned. It is quicker to check for this case and pass
409 * the rect to the simpler intersection test.
410 */
411
412 // Prevent floating point comparison errors
413 static const EDA_ANGLE ROT_EPSILON( 0.000000001, DEGREES_T );
414
415 static const EDA_ANGLE ROT_PARALLEL[] = { ANGLE_0, ANGLE_180, ANGLE_360 };
416 static const EDA_ANGLE ROT_PERPENDICULAR[] = { ANGLE_0, ANGLE_90, ANGLE_270 };
417
418 // Test for non-rotated rectangle
419 for( EDA_ANGLE ii : ROT_PARALLEL )
420 {
421 if( std::abs( rotation - ii ) < ROT_EPSILON )
422 return Intersects( aRect );
423 }
424
425 // Test for rectangle rotated by multiple of 90 degrees
426 for( EDA_ANGLE jj : ROT_PERPENDICULAR )
427 {
428 if( std::abs( rotation - jj ) < ROT_EPSILON )
429 {
430 BOX2<Vec> rotRect;
431
432 // Rotate the supplied rect by 90 degrees
433 rotRect.SetOrigin( aRect.Centre() );
434 rotRect.Inflate( aRect.GetHeight(), aRect.GetWidth() );
435 return Intersects( rotRect );
436 }
437 }
438
439 /* There is some non-orthogonal rotation.
440 * There are three cases to test:
441 * A) One point of this rect is inside the rotated rect
442 * B) One point of the rotated rect is inside this rect
443 * C) One of the sides of the rotated rect intersect this
444 */
445
446 VECTOR2I corners[4];
447
448 /* Test A : Any corners exist in rotated rect? */
449 corners[0] = VECTOR2I( GetLeft(), GetTop() );
450 corners[1] = VECTOR2I( GetRight(), GetTop() );
451 corners[2] = VECTOR2I( GetRight(), GetBottom() );
452 corners[3] = VECTOR2I( GetLeft(), GetBottom() );
453
454 VECTOR2I rCentre = aRect.Centre();
455
456 for( int i = 0; i < 4; i++ )
457 {
458 VECTOR2I delta = corners[i] - rCentre;
459 RotatePoint( delta, -rotation );
460 delta += rCentre;
461
462 if( aRect.Contains( delta ) )
463 return true;
464 }
465
466 /* Test B : Any corners of rotated rect exist in this one? */
469
470 // Construct corners around center of shape
471 corners[0] = VECTOR2I( -w, -h );
472 corners[1] = VECTOR2I( w, -h );
473 corners[2] = VECTOR2I( w, h );
474 corners[3] = VECTOR2I( -w, h );
475
476 // Rotate and test each corner
477 for( int j = 0; j < 4; j++ )
478 {
479 RotatePoint( corners[j], rotation );
480 corners[j] += rCentre;
481
482 if( Contains( corners[j] ) )
483 return true;
484 }
485
486 /* Test C : Any sides of rotated rect intersect this */
487 if( Intersects( corners[0], corners[1] ) || Intersects( corners[1], corners[2] )
488 || Intersects( corners[2], corners[3] ) || Intersects( corners[3], corners[0] ) )
489 {
490 return true;
491 }
492
493 return false;
494 }
495
499 bool IntersectsCircle( const Vec& aCenter, const int aRadius ) const
500 {
501 if( !m_init )
502 return false;
503
504 Vec closest = NearestPoint( aCenter );
505
506 double dx = static_cast<double>( aCenter.x ) - closest.x;
507 double dy = static_cast<double>( aCenter.y ) - closest.y;
508
509 double r = static_cast<double>( aRadius );
510
511 return ( dx * dx + dy * dy ) <= ( r * r );
512 }
513
518 bool IntersectsCircleEdge( const Vec& aCenter, const int aRadius, const int aWidth ) const
519 {
520 if( !m_init )
521 return false;
522
523 BOX2<Vec> me( *this );
524 me.Normalize(); // ensure size is >= 0
525
526 // Test if the circle intersects at all
527 if( !IntersectsCircle( aCenter, aRadius + aWidth / 2 ) )
528 return false;
529
530 Vec farpt = FarthestPointTo( aCenter );
531 // Farthest point must be further than the inside of the line
532 double fx = (double) farpt.x - aCenter.x;
533 double fy = (double) farpt.y - aCenter.y;
534
535 double r = (double) aRadius - (double) aWidth / 2;
536
537 return ( fx * fx + fy * fy ) > ( r * r );
538 }
539
540 const std::string Format() const
541 {
542 std::stringstream ss;
543
544 ss << "( box corner " << m_Pos.Format() << " w " << m_Size.x << " h " << m_Size.y << " )";
545
546 return ss.str();
547 }
548
554 {
555 if( m_Size.x >= 0 )
556 {
557 if( m_Size.x < -2 * dx )
558 {
559 // Don't allow deflate to eat more width than we have,
561 m_Size.x = 0;
562 }
563 else
564 {
565 // The inflate is valid.
566 m_Pos.x -= dx;
567 m_Size.x += 2 * dx;
568 }
569 }
570 else // size.x < 0:
571 {
572 if( m_Size.x > 2 * dx )
573 {
574 // Don't allow deflate to eat more width than we have,
576 m_Size.x = 0;
577 }
578 else
579 {
580 // The inflate is valid.
581 m_Pos.x += dx;
582 m_Size.x -= 2 * dx; // m_Size.x <0: inflate when dx > 0
583 }
584 }
585
586 if( m_Size.y >= 0 )
587 {
588 if( m_Size.y < -2 * dy )
589 {
590 // Don't allow deflate to eat more height than we have,
592 m_Size.y = 0;
593 }
594 else
595 {
596 // The inflate is valid.
597 m_Pos.y -= dy;
598 m_Size.y += 2 * dy;
599 }
600 }
601 else // size.y < 0:
602 {
603 if( m_Size.y > 2 * dy )
604 {
605 // Don't allow deflate to eat more height than we have,
607 m_Size.y = 0;
608 }
609 else
610 {
611 // The inflate is valid.
612 m_Pos.y += dy;
613 m_Size.y -= 2 * dy; // m_Size.y <0: inflate when dy > 0
614 }
615 }
616
617 return *this;
618 }
619
624 constexpr BOX2<Vec>& Inflate( coord_type aDelta )
625 {
626 Inflate( aDelta, aDelta );
627 return *this;
628 }
629
633 constexpr BOX2<Vec> GetInflated( coord_type aDx, coord_type aDy ) const
634 {
635 BOX2<Vec> ret( *this );
636 ret.Inflate( aDx, aDy );
637 return ret;
638 }
639
643 constexpr BOX2<Vec> GetInflated( coord_type aDelta ) const
644 {
645 return GetInflated( aDelta, aDelta );
646 }
647
653 constexpr BOX2<Vec>& Merge( const BOX2<Vec>& aRect )
654 {
655 if( !m_init )
656 {
657 if( aRect.m_init )
658 {
659 m_Pos = aRect.GetPosition();
660 m_Size = aRect.GetSize();
661 m_init = true;
662 }
663
664 return *this;
665 }
666
667 Normalize(); // ensure width and height >= 0
668 BOX2<Vec> rect = aRect;
669 rect.Normalize(); // ensure width and height >= 0
670 Vec end = GetEnd();
671 Vec rect_end = rect.GetEnd();
672
673 // Change origin and size in order to contain the given rect
674 m_Pos.x = std::min( m_Pos.x, rect.m_Pos.x );
675 m_Pos.y = std::min( m_Pos.y, rect.m_Pos.y );
676 end.x = std::max( end.x, rect_end.x );
677 end.y = std::max( end.y, rect_end.y );
678 SetEnd( end );
679 return *this;
680 }
681
687 constexpr BOX2<Vec>& Merge( const Vec& aPoint )
688 {
689 if( !m_init )
690 {
691 m_Pos = aPoint;
692 m_Size = VECTOR2I( 0, 0 );
693 m_init = true;
694 return *this;
695 }
696
697 Normalize(); // ensure width and height >= 0
698
699 Vec end = GetEnd();
700
701 // Change origin and size in order to contain the given rectangle.
702 m_Pos.x = std::min( m_Pos.x, aPoint.x );
703 m_Pos.y = std::min( m_Pos.y, aPoint.y );
704 end.x = std::max( end.x, aPoint.x );
705 end.y = std::max( end.y, aPoint.y );
706 SetEnd( end );
707 return *this;
708 }
709
715 const BOX2<Vec> GetBoundingBoxRotated( const VECTOR2I& aRotCenter,
716 const EDA_ANGLE& aAngle ) const
717 {
718 VECTOR2I corners[4];
719
720 // Build the corners list
721 corners[0] = GetOrigin();
722 corners[2] = GetEnd();
723 corners[1].x = corners[0].x;
724 corners[1].y = corners[2].y;
725 corners[3].x = corners[2].x;
726 corners[3].y = corners[0].y;
727
728 // Rotate all corners, to find the bounding box
729 for( int ii = 0; ii < 4; ii++ )
730 RotatePoint( corners[ii], aRotCenter, aAngle );
731
732 // Find the corners bounding box
733 VECTOR2I start = corners[0];
734 VECTOR2I end = corners[0];
735
736 for( int ii = 1; ii < 4; ii++ )
737 {
738 start.x = std::min( start.x, corners[ii].x );
739 start.y = std::min( start.y, corners[ii].y );
740 end.x = std::max( end.x, corners[ii].x );
741 end.y = std::max( end.y, corners[ii].y );
742 }
743
744 BOX2<Vec> bbox;
745 bbox.SetOrigin( start );
746 bbox.SetEnd( end );
747
748 return bbox;
749 }
750
756 constexpr ecoord_type GetArea() const
757 {
758 return (ecoord_type) GetWidth() * (ecoord_type) GetHeight();
759 }
760
767 {
768 return m_Size.EuclideanNorm();
769 }
770
776 constexpr ecoord_type SquaredDiagonal() const
777 {
778 return m_Size.SquaredEuclideanNorm();
779 }
780
781 constexpr ecoord_type SquaredDistance( const Vec& aP ) const
782 {
783 ecoord_type x2 = m_Pos.x + m_Size.x;
784 ecoord_type y2 = m_Pos.y + m_Size.y;
785 ecoord_type xdiff = std::max( aP.x < m_Pos.x ? m_Pos.x - aP.x : m_Pos.x - x2,
786 (ecoord_type) 0 );
787 ecoord_type ydiff = std::max( aP.y < m_Pos.y ? m_Pos.y - aP.y : m_Pos.y - y2,
788 (ecoord_type) 0 );
789 return xdiff * xdiff + ydiff * ydiff;
790 }
791
792 ecoord_type Distance( const Vec& aP ) const
793 {
794 const double dist = std::sqrt( static_cast<double>( SquaredDistance( aP ) ) );
795
796 if constexpr( std::is_floating_point<ecoord_type>() )
797 return static_cast<ecoord_type>( dist );
798 else
799 return KiROUND<double, ecoord_type>( dist );
800 }
801
808 constexpr ecoord_type SquaredDistance( const BOX2<Vec>& aBox ) const
809 {
810 ecoord_type s = 0;
811
812 if( aBox.m_Pos.x + aBox.m_Size.x < m_Pos.x )
813 {
814 ecoord_type d = aBox.m_Pos.x + aBox.m_Size.x - m_Pos.x;
815 s += d * d;
816 }
817 else if( aBox.m_Pos.x > m_Pos.x + m_Size.x )
818 {
819 ecoord_type d = aBox.m_Pos.x - m_Size.x - m_Pos.x;
820 s += d * d;
821 }
822
823 if( aBox.m_Pos.y + aBox.m_Size.y < m_Pos.y )
824 {
825 ecoord_type d = aBox.m_Pos.y + aBox.m_Size.y - m_Pos.y;
826 s += d * d;
827 }
828 else if( aBox.m_Pos.y > m_Pos.y + m_Size.y )
829 {
830 ecoord_type d = aBox.m_Pos.y - m_Size.y - m_Pos.y;
831 s += d * d;
832 }
833
834 return s;
835 }
836
843 ecoord_type Distance( const BOX2<Vec>& aBox ) const
844 {
845 const double dist = std::sqrt( static_cast<double>( SquaredDistance( aBox ) ) );
846
847 if constexpr( std::is_floating_point<ecoord_type>() )
848 return static_cast<ecoord_type>( dist );
849 else
850 return KiROUND<double, ecoord_type>( dist );
851 }
852
856 constexpr Vec NearestPoint( const Vec& aPoint ) const
857 {
858 BOX2<Vec> me( *this );
859
860 me.Normalize(); // ensure size is >= 0
861
862 // Determine closest point to the circle centre within this rect
863 const coord_type nx = std::clamp( aPoint.x, me.GetLeft(), me.GetRight() );
864 const coord_type ny = std::clamp( aPoint.y, me.GetTop(), me.GetBottom() );
865
866 return Vec( nx, ny );
867 }
868
872 constexpr Vec FarthestPointTo( const Vec& aPoint ) const
873 {
874 BOX2<Vec> me( *this );
875
876 me.Normalize(); // ensure size is >= 0
877
878 coord_type fx;
879 coord_type fy;
880
881 Vec center = me.GetCenter();
882
883 if( aPoint.x < center.x )
884 fx = me.GetRight();
885 else
886 fx = me.GetLeft();
887
888 if( aPoint.y < center.y )
889 fy = me.GetBottom();
890 else
891 fy = me.GetTop();
892
893 return Vec( fx, fy );
894 }
895
896 constexpr bool operator==( const BOX2<Vec>& aOther ) const
897 {
898 auto t1 ( *this );
899 auto t2 ( aOther );
900 t1.Normalize();
901 t2.Normalize();
902 return ( t1.m_Pos == t2.m_Pos && t1.m_Size == t2.m_Size );
903 }
904
905 constexpr bool operator!=( const BOX2<Vec>& aOther ) const
906 {
907 auto t1 ( *this );
908 auto t2 ( aOther );
909 t1.Normalize();
910 t2.Normalize();
911 return ( t1.m_Pos != t2.m_Pos || t1.m_Size != t2.m_Size );
912 }
913
914 constexpr bool IsValid() const
915 {
916 return m_init;
917 }
918
919private:
920 Vec m_Pos; // Rectangle Origin
921 SizeVec m_Size; // Rectangle Size
922
923 bool m_init; // Is the rectangle initialized
924};
925
926/* Default specializations */
930
931typedef std::optional<BOX2I> OPT_BOX2I;
932
933
934inline constexpr BOX2I BOX2ISafe( const BOX2D& aInput )
935{
936 constexpr double high = std::numeric_limits<int>::max();
937 constexpr double low = -std::numeric_limits<int>::max();
938
939 int left = (int) std::clamp( aInput.GetLeft(), low, high );
940 int top = (int) std::clamp( aInput.GetTop(), low, high );
941
942 int64_t right = (int64_t) std::clamp( aInput.GetRight(), low, high );
943 int64_t bottom = (int64_t) std::clamp( aInput.GetBottom(), low, high );
944
945 return BOX2I( VECTOR2I( left, top ), VECTOR2L( right - left, bottom - top ) );
946}
947
948
953template <typename Vec>
954inline constexpr bool IsBOX2Safe( const BOX2<Vec>& aInput )
955{
956 constexpr double high = std::numeric_limits<int>::max();
957 constexpr double low = -std::numeric_limits<int>::max();
958
959 return ( aInput.GetLeft() >= low && aInput.GetTop() >= low &&
960 aInput.GetRight() <= high && aInput.GetBottom() <= high );
961}
962
963
964inline constexpr BOX2I BOX2ISafe( const VECTOR2D& aPos, const VECTOR2D& aSize )
965{
966 constexpr double high = std::numeric_limits<int>::max();
967 constexpr double low = -std::numeric_limits<int>::max();
968
969 int left = (int) std::clamp( aPos.x, low, high );
970 int top = (int) std::clamp( aPos.y, low, high );
971
972 int64_t right = (int64_t) std::clamp( aPos.x + aSize.x, low, high );
973 int64_t bottom = (int64_t) std::clamp( aPos.y + aSize.y, low, high );
974
975 return BOX2I( VECTOR2I( left, top ), VECTOR2L( right - left, bottom - top ) );
976}
977
978
979template <typename S, std::enable_if_t<std::is_integral<S>::value, int> = 0>
980inline constexpr BOX2I BOX2ISafe( const VECTOR2I& aPos, const VECTOR2<S>& aSize )
981{
982 constexpr int64_t high = std::numeric_limits<int>::max();
983 constexpr int64_t low = -std::numeric_limits<int>::max();
984
985 int64_t ext_right = int64_t( aPos.x ) + aSize.x;
986 int64_t ext_bottom = int64_t( aPos.y ) + aSize.y;
987
988 int64_t right = std::clamp( ext_right, low, high );
989 int64_t bottom = std::clamp( ext_bottom, low, high );
990
991 return BOX2I( aPos, VECTOR2L( right - aPos.x, bottom - aPos.y ) );
992}
993
994/* KiROUND specialization for double -> int boxes */
995inline constexpr BOX2I KiROUND( const BOX2D& aBoxD )
996{
997 return BOX2I( KiROUND( aBoxD.GetOrigin() ), KiROUND( aBoxD.GetSize() ) );
998}
999
1000#endif
constexpr bool IsBOX2Safe(const BOX2< Vec > &aInput)
Check if a BOX2 is safe for use with BOX2D (probably BOX2D or BOX2L)
Definition box2.h:954
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition box2.h:934
BOX2< VECTOR2L > BOX2L
Definition box2.h:929
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
std::optional< BOX2I > OPT_BOX2I
Definition box2.h:931
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
BOX2< VECTOR2D > BOX2D
Definition box2.h:928
A 2D bounding box built on top of an origin point and size vector.
Definition box2.h:41
constexpr BOX2< Vec > Intersect(const BOX2< Vec > &aRect)
Definition box2.h:344
constexpr ecoord_type SquaredDistance(const BOX2< Vec > &aBox) const
Return the square of the minimum distance between self and box aBox.
Definition box2.h:808
constexpr const Vec & GetPosition() const
Definition box2.h:208
constexpr int GetSizeMax() const
Definition box2.h:232
constexpr void SetMaximum()
Definition box2.h:77
Vec::extended_type size_type
Definition box2.h:44
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
static constexpr BOX2< Vec > ByCorners(const Vec &aCorner1, const Vec &aCorner2)
Definition box2.h:67
constexpr bool operator==(const BOX2< Vec > &aOther) const
Definition box2.h:896
ecoord_type Distance(const BOX2< Vec > &aBox) const
Return the minimum distance between self and aBox.
Definition box2.h:843
constexpr void SetHeight(size_type val)
Definition box2.h:289
const std::string Format() const
Definition box2.h:540
constexpr BOX2< Vec > & Inflate(coord_type aDelta)
Inflate the rectangle horizontally and vertically by aDelta.
Definition box2.h:624
constexpr const Vec GetEnd() const
Definition box2.h:209
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:234
bool Intersects(const BOX2< Vec > &aRect, const EDA_ANGLE &aRotation) const
Definition box2.h:399
constexpr ecoord_type SquaredDiagonal() const
Return the square of the length of the diagonal of the rectangle.
Definition box2.h:776
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr Vec NearestPoint(const Vec &aPoint) const
Return the point in this rect that is closest to the provided point.
Definition box2.h:856
ecoord_type Diagonal() const
Return the length of the diagonal of the rectangle.
Definition box2.h:766
constexpr coord_type GetY() const
Definition box2.h:205
bool Intersects(const Vec &aPoint1, const Vec &aPoint2) const
Definition box2.h:370
static constexpr BOX2< Vec > ByCenter(const Vec &aCenter, const SizeVec &aSize)
Definition box2.h:72
VECTOR2I m_Pos
Definition box2.h:920
constexpr BOX2()
Definition box2.h:49
constexpr bool operator!=(const BOX2< Vec > &aOther) const
Definition box2.h:905
constexpr void SetSize(size_type w, size_type h)
Definition box2.h:251
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr Vec Centre() const
Definition box2.h:94
Vec::extended_type ecoord_type
Definition box2.h:45
constexpr coord_type GetX() const
Definition box2.h:204
constexpr void SetEnd(const Vec &pos)
Definition box2.h:299
bool IntersectsCircleEdge(const Vec &aCenter, const int aRadius, const int aWidth) const
Definition box2.h:518
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:653
bool IntersectsCircle(const Vec &aCenter, const int aRadius) const
Definition box2.h:499
constexpr BOX2(const Vec &aPos, const SizeVec &aSize=SizeVec(0, 0))
Definition box2.h:55
VECTOR2< size_type > SizeVec
Definition box2.h:46
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
Definition box2.h:756
constexpr const Vec GetCenter() const
Definition box2.h:227
constexpr void SetSize(const SizeVec &size)
Definition box2.h:245
std::numeric_limits< coord_type > coord_limits
Definition box2.h:47
constexpr void Offset(const Vec &offset)
Definition box2.h:262
SizeVec m_Size
Definition box2.h:921
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr void SetOrigin(coord_type x, coord_type y)
Definition box2.h:240
constexpr void SetWidth(size_type val)
Definition box2.h:284
constexpr bool Contains(const BOX2< Vec > &aRect) const
Definition box2.h:198
Vec::coord_type coord_type
Definition box2.h:43
constexpr void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition box2.h:135
constexpr BOX2< Vec > GetInflated(coord_type aDelta) const
Get a new rectangle that is this one, inflated by aDelta.
Definition box2.h:643
ecoord_type Distance(const Vec &aP) const
Definition box2.h:792
constexpr BOX2< Vec > GetWithOffset(const Vec &aMoveVector) const
Definition box2.h:267
constexpr void SetX(coord_type val)
Definition box2.h:274
constexpr bool Contains(coord_type x, coord_type y) const
Definition box2.h:191
constexpr ecoord_type SquaredDistance(const Vec &aP) const
Definition box2.h:781
constexpr BOX2< Vec > GetInflated(coord_type aDx, coord_type aDy) const
Get a new rectangle that is this one, inflated by aDx and aDy.
Definition box2.h:633
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr void SetY(coord_type val)
Definition box2.h:279
constexpr bool IsValid() const
Definition box2.h:914
const BOX2< Vec > GetBoundingBoxRotated(const VECTOR2I &aRotCenter, const EDA_ANGLE &aAngle) const
Useful to calculate bounding box of rotated items, when rotation is not cardinal.
Definition box2.h:715
constexpr coord_type GetRight() const
Definition box2.h:214
void Compute(const Container &aPointList)
Compute the bounding box from a given list of points.
Definition box2.h:106
constexpr const SizeVec & GetSize() const
Definition box2.h:203
constexpr BOX2< Vec > & Merge(const Vec &aPoint)
Modify the position and size of the rectangle in order to contain the given point.
Definition box2.h:687
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:294
constexpr coord_type GetTop() const
Definition box2.h:226
constexpr void Offset(coord_type dx, coord_type dy)
Definition box2.h:256
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
constexpr coord_type GetBottom() const
Definition box2.h:219
constexpr Vec FarthestPointTo(const Vec &aPoint) const
Return the point in this rect that is farthest from the provided point.
Definition box2.h:872
EDA_ANGLE Normalize()
Definition eda_angle.h:229
Define a general 2D-vector/point.
Definition vector2d.h:67
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:422
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:424
@ DEGREES_T
Definition eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:427
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:428
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:426
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:411
KIBIS top(path, &reporter)
VECTOR2I center
VECTOR2I end
int delta
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:225
bool SegmentIntersectsSegment(const VECTOR2I &a_p1_l1, const VECTOR2I &a_p2_l1, const VECTOR2I &a_p1_l2, const VECTOR2I &a_p2_l2, VECTOR2I *aIntersectionPoint=nullptr)
Test if two lines intersect.
Definition trigo.cpp:103
constexpr ret_type KiCheckedCast(in_type v)
Perform a cast between numerical types.
Definition util.h:65
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:684