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 (C) 2012-2023 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, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#ifndef __BOX2_H
28#define __BOX2_H
29
30#include <algorithm>
31#include <limits>
32#include <optional>
33
34#include <math/vector2d.h>
35#include <geometry/eda_angle.h>
36#include <core/kicad_algo.h>
37#include <trigo.h>
38
42template <class Vec>
43class BOX2
44{
45public:
46 typedef typename Vec::coord_type coord_type;
47 typedef typename Vec::extended_type size_type;
48 typedef typename Vec::extended_type ecoord_type;
50 typedef std::numeric_limits<coord_type> coord_limits;
51
52 BOX2() :
53 m_Pos( 0, 0 ),
54 m_Size( 0, 0 ),
55 m_init( false )
56 {};
57
58 BOX2( const Vec& aPos, const SizeVec& aSize = SizeVec(0, 0) ) :
59 m_Pos( aPos ),
60 m_Size( aSize ),
61 m_init( true )
62 {
63 // Range check
64 KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) + m_Size.x );
65 KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) + m_Size.y );
66
67 Normalize();
68 }
69
71 {
72 if constexpr( std::is_floating_point<coord_type>() )
73 {
74 m_Pos.x = m_Pos.y = coord_limits::lowest() / 2.0;
75 m_Size.x = m_Size.y = coord_limits::max();
76 }
77 else
78 {
79 // We want to be able to invert the box, so don't use lowest()
80 m_Pos.x = m_Pos.y = -coord_limits::max();
81 m_Size.x = m_Size.y = size_type( coord_limits::max() ) + coord_limits::max();
82 }
83
84 m_init = true;
85 }
86
87 Vec Centre() const
88 {
89 return Vec( KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) + m_Size.x / 2 ),
90 KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) + m_Size.y / 2 ) );
91 }
92
98 template <class Container>
99 void Compute( const Container& aPointList )
100 {
101 Vec vmin, vmax;
102
103 typename Container::const_iterator i;
104
105 if( !aPointList.size() )
106 return;
107
108 vmin = vmax = aPointList[0];
109
110 for( i = aPointList.begin(); i != aPointList.end(); ++i )
111 {
112 Vec p( *i );
113 vmin.x = std::min( vmin.x, p.x );
114 vmin.y = std::min( vmin.y, p.y );
115 vmax.x = std::max( vmax.x, p.x );
116 vmax.y = std::max( vmax.y, p.y );
117 }
118
119 SetOrigin( vmin );
120 SetSize( vmax - vmin );
121 }
122
128 void Move( const Vec& aMoveVector )
129 {
130 m_Pos += aMoveVector;
131 }
132
137 {
138 if( m_Size.y < 0 )
139 {
140 m_Size.y = -m_Size.y;
141 m_Pos.y = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) - m_Size.y );
142 }
143
144 if( m_Size.x < 0 )
145 {
146 m_Size.x = -m_Size.x;
147 m_Pos.x = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) - m_Size.x );
148 }
149
150 return *this;
151 }
152
158 bool Contains( const Vec& aPoint ) const
159 {
160 Vec rel_pos = aPoint - m_Pos;
161 Vec size = m_Size;
162
163 if( size.x < 0 )
164 {
165 size.x = -size.x;
166 rel_pos.x += size.x;
167 }
168
169 if( size.y < 0 )
170 {
171 size.y = -size.y;
172 rel_pos.y += size.y;
173 }
174
175 return ( rel_pos.x >= 0 ) && ( rel_pos.y >= 0 ) && ( rel_pos.y <= size.y) &&
176 ( rel_pos.x <= size.x);
177 }
178
184 bool Contains( coord_type x, coord_type y ) const { return Contains( Vec( x, y ) ); }
185
191 bool Contains( const BOX2<Vec>& aRect ) const
192 {
193 return Contains( aRect.GetOrigin() ) && Contains( aRect.GetEnd() );
194 }
195
196 const SizeVec& GetSize() const { return m_Size; }
197 coord_type GetX() const { return m_Pos.x; }
198 coord_type GetY() const { return m_Pos.y; }
199
200 const Vec& GetOrigin() const { return m_Pos; }
201 const Vec& GetPosition() const { return m_Pos; }
202 const Vec GetEnd() const { return Vec( GetRight(), GetBottom() ); }
203
204 size_type GetWidth() const { return m_Size.x; }
205 size_type GetHeight() const { return m_Size.y; }
206
208 {
209 return KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) + m_Size.x );
210 }
211
213 {
214 return KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) + m_Size.y );
215 }
216
217 // Compatibility aliases
218 coord_type GetLeft() const { return GetX(); }
219 coord_type GetTop() const { return GetY(); }
220 const Vec GetCenter() const { return Centre(); }
221
225 int GetSizeMax() const { return ( m_Size.x > m_Size.y ) ? m_Size.x : m_Size.y; }
226
227 void SetOrigin( const Vec& pos )
228 {
229 m_Pos = pos;
230 m_init = true;
231 }
232
234 {
235 SetOrigin( Vec( x, y ) );
236 }
237
238 void SetSize( const SizeVec& size )
239 {
240 m_Size = size;
241 m_init = true;
242 }
243
245 {
246 SetSize( SizeVec( w, h ) );
247 }
248
250 {
251 m_Pos.x += dx;
252 m_Pos.y += dy;
253 }
254
255 void Offset( const Vec& offset )
256 {
257 Offset( offset.x, offset.y );
258 }
259
260 void SetX( coord_type val )
261 {
262 SetOrigin( val, m_Pos.y );
263 }
264
265 void SetY( coord_type val )
266 {
267 SetOrigin( m_Pos.x, val );
268 }
269
270 void SetWidth( size_type val )
271 {
272 SetSize( val, m_Size.y );
273 }
274
276 {
277 SetSize( m_Size.x, val );
278 }
279
281 {
282 SetEnd( Vec( x, y ) );
283 }
284
285 void SetEnd( const Vec& pos )
286 {
287 SetSize( SizeVec( pos ) - m_Pos );
288 }
289
294 bool Intersects( const BOX2<Vec>& aRect ) const
295 {
296 // this logic taken from wxWidgets' geometry.cpp file:
297 bool rc;
298
299 BOX2<Vec> me( *this );
300 BOX2<Vec> rect( aRect );
301 me.Normalize(); // ensure size is >= 0
302 rect.Normalize(); // ensure size is >= 0
303
304 // calculate the left common area coordinate:
305 ecoord_type left = std::max( me.m_Pos.x, rect.m_Pos.x );
306
307 // calculate the right common area coordinate:
308 ecoord_type right = std::min( ecoord_type( me.m_Pos.x ) + me.m_Size.x,
309 ecoord_type( rect.m_Pos.x ) + rect.m_Size.x );
310
311 // calculate the upper common area coordinate:
312 ecoord_type top = std::max( me.m_Pos.y, rect.m_Pos.y );
313
314 // calculate the lower common area coordinate:
315 ecoord_type bottom = std::min( ecoord_type( me.m_Pos.y ) + me.m_Size.y,
316 ecoord_type( rect.m_Pos.y ) + rect.m_Size.y );
317
318 // if a common area exists, it must have a positive (null accepted) size
319 if( left <= right && top <= bottom )
320 rc = true;
321 else
322 rc = false;
323
324 return rc;
325 }
326
331 {
332 BOX2<Vec> me( *this );
333 BOX2<Vec> rect( aRect );
334 me.Normalize(); // ensure size is >= 0
335 rect.Normalize(); // ensure size is >= 0
336
337 Vec topLeft, bottomRight;
338
339 topLeft.x = std::max( me.m_Pos.x, rect.m_Pos.x );
340
341 bottomRight.x = std::min( size_type( me.m_Pos.x ) + me.m_Size.x,
342 size_type( rect.m_Pos.x ) + rect.m_Size.x );
343
344 topLeft.y = std::max( me.m_Pos.y, rect.m_Pos.y );
345
346 bottomRight.y = std::min( size_type( me.m_Pos.y ) + me.m_Size.y,
347 size_type( rect.m_Pos.y ) + rect.m_Size.y );
348
349 if( topLeft.x < bottomRight.x && topLeft.y < bottomRight.y )
350 return BOX2<Vec>( topLeft, SizeVec( bottomRight ) - topLeft );
351 else
352 return BOX2<Vec>( Vec( 0, 0 ), SizeVec( 0, 0 ) );
353 }
354
358 bool Intersects( const Vec& aPoint1, const Vec& aPoint2 ) const
359 {
360 Vec point2, point4;
361
362 if( Contains( aPoint1 ) || Contains( aPoint2 ) )
363 return true;
364
365 point2.x = GetEnd().x;
366 point2.y = GetOrigin().y;
367 point4.x = GetOrigin().x;
368 point4.y = GetEnd().y;
369
370 //Only need to test 3 sides since a straight line can't enter and exit on same side
371 if( SegmentIntersectsSegment( aPoint1, aPoint2, GetOrigin(), point2 ) )
372 return true;
373
374 if( SegmentIntersectsSegment( aPoint1, aPoint2, point2, GetEnd() ) )
375 return true;
376
377 if( SegmentIntersectsSegment( aPoint1, aPoint2, GetEnd(), point4 ) )
378 return true;
379
380 return false;
381 }
382
387 bool Intersects( const BOX2<Vec>& aRect, const EDA_ANGLE& aRotation ) const
388 {
389 if( !m_init )
390 return false;
391
392 EDA_ANGLE rotation = aRotation;
393 rotation.Normalize();
394
395 /*
396 * Most rectangles will be axis aligned. It is quicker to check for this case and pass
397 * the rect to the simpler intersection test.
398 */
399
400 // Prevent floating point comparison errors
401 static const EDA_ANGLE ROT_EPSILON( 0.000000001, DEGREES_T );
402
403 static const EDA_ANGLE ROT_PARALLEL[] = { ANGLE_0, ANGLE_180, ANGLE_360 };
404 static const EDA_ANGLE ROT_PERPENDICULAR[] = { ANGLE_0, ANGLE_90, ANGLE_270 };
405
406 // Test for non-rotated rectangle
407 for( EDA_ANGLE ii : ROT_PARALLEL )
408 {
409 if( std::abs( rotation - ii ) < ROT_EPSILON )
410 return Intersects( aRect );
411 }
412
413 // Test for rectangle rotated by multiple of 90 degrees
414 for( EDA_ANGLE jj : ROT_PERPENDICULAR )
415 {
416 if( std::abs( rotation - jj ) < ROT_EPSILON )
417 {
418 BOX2<Vec> rotRect;
419
420 // Rotate the supplied rect by 90 degrees
421 rotRect.SetOrigin( aRect.Centre() );
422 rotRect.Inflate( aRect.GetHeight(), aRect.GetWidth() );
423 return Intersects( rotRect );
424 }
425 }
426
427 /* There is some non-orthogonal rotation.
428 * There are three cases to test:
429 * A) One point of this rect is inside the rotated rect
430 * B) One point of the rotated rect is inside this rect
431 * C) One of the sides of the rotated rect intersect this
432 */
433
434 VECTOR2I corners[4];
435
436 /* Test A : Any corners exist in rotated rect? */
437 corners[0] = VECTOR2I( GetLeft(), GetTop() );
438 corners[1] = VECTOR2I( GetRight(), GetTop() );
439 corners[2] = VECTOR2I( GetRight(), GetBottom() );
440 corners[3] = VECTOR2I( GetLeft(), GetBottom() );
441
442 VECTOR2I rCentre = aRect.Centre();
443
444 for( int i = 0; i < 4; i++ )
445 {
446 VECTOR2I delta = corners[i] - rCentre;
447 RotatePoint( delta, -rotation );
448 delta += rCentre;
449
450 if( aRect.Contains( delta ) )
451 return true;
452 }
453
454 /* Test B : Any corners of rotated rect exist in this one? */
455 int w = KiCheckedCast<ecoord_type, coord_type>( aRect.GetWidth() / 2 );
456 int h = KiCheckedCast<ecoord_type, coord_type>( aRect.GetHeight() / 2 );
457
458 // Construct corners around center of shape
459 corners[0] = VECTOR2I( -w, -h );
460 corners[1] = VECTOR2I( w, -h );
461 corners[2] = VECTOR2I( w, h );
462 corners[3] = VECTOR2I( -w, h );
463
464 // Rotate and test each corner
465 for( int j = 0; j < 4; j++ )
466 {
467 RotatePoint( corners[j], rotation );
468 corners[j] += rCentre;
469
470 if( Contains( corners[j] ) )
471 return true;
472 }
473
474 /* Test C : Any sides of rotated rect intersect this */
475 if( Intersects( corners[0], corners[1] ) || Intersects( corners[1], corners[2] )
476 || Intersects( corners[2], corners[3] ) || Intersects( corners[3], corners[0] ) )
477 {
478 return true;
479 }
480
481 return false;
482 }
483
487 bool IntersectsCircle( const Vec& aCenter, const int aRadius ) const
488 {
489 if( !m_init )
490 return false;
491
492 Vec closest = ClosestPointTo( aCenter );
493
494 double dx = static_cast<double>( aCenter.x ) - closest.x;
495 double dy = static_cast<double>( aCenter.y ) - closest.y;
496
497 double r = static_cast<double>( aRadius );
498
499 return ( dx * dx + dy * dy ) <= ( r * r );
500 }
501
506 bool IntersectsCircleEdge( const Vec& aCenter, const int aRadius, const int aWidth ) const
507 {
508 if( !m_init )
509 return false;
510
511 BOX2<Vec> me( *this );
512 me.Normalize(); // ensure size is >= 0
513
514 // Test if the circle intersects at all
515 if( !IntersectsCircle( aCenter, aRadius + aWidth / 2 ) )
516 return false;
517
518 Vec farpt = FarthestPointTo( aCenter );
519 // Farthest point must be further than the inside of the line
520 double fx = (double) farpt.x - aCenter.x;
521 double fy = (double) farpt.y - aCenter.y;
522
523 double r = (double) aRadius - (double) aWidth / 2;
524
525 return ( fx * fx + fy * fy ) > ( r * r );
526 }
527
528 const std::string Format() const
529 {
530 std::stringstream ss;
531
532 ss << "( box corner " << m_Pos.Format() << " w " << m_Size.x << " h " << m_Size.y << " )";
533
534 return ss.str();
535 }
536
542 {
543 if( m_Size.x >= 0 )
544 {
545 if( m_Size.x < -2 * dx )
546 {
547 // Don't allow deflate to eat more width than we have,
548 m_Pos.x = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) + m_Size.x / 2 );
549 m_Size.x = 0;
550 }
551 else
552 {
553 // The inflate is valid.
554 m_Pos.x -= dx;
555 m_Size.x += 2 * dx;
556 }
557 }
558 else // size.x < 0:
559 {
560 if( m_Size.x > 2 * dx )
561 {
562 // Don't allow deflate to eat more width than we have,
563 m_Pos.x = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) - m_Size.x / 2 );
564 m_Size.x = 0;
565 }
566 else
567 {
568 // The inflate is valid.
569 m_Pos.x += dx;
570 m_Size.x -= 2 * dx; // m_Size.x <0: inflate when dx > 0
571 }
572 }
573
574 if( m_Size.y >= 0 )
575 {
576 if( m_Size.y < -2 * dy )
577 {
578 // Don't allow deflate to eat more height than we have,
579 m_Pos.y = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) + m_Size.y / 2 );
580 m_Size.y = 0;
581 }
582 else
583 {
584 // The inflate is valid.
585 m_Pos.y -= dy;
586 m_Size.y += 2 * dy;
587 }
588 }
589 else // size.y < 0:
590 {
591 if( m_Size.y > 2 * dy )
592 {
593 // Don't allow deflate to eat more height than we have,
594 m_Pos.y = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) - m_Size.y / 2 );
595 m_Size.y = 0;
596 }
597 else
598 {
599 // The inflate is valid.
600 m_Pos.y += dy;
601 m_Size.y -= 2 * dy; // m_Size.y <0: inflate when dy > 0
602 }
603 }
604
605 return *this;
606 }
607
612 BOX2<Vec>& Inflate( int aDelta )
613 {
614 Inflate( aDelta, aDelta );
615 return *this;
616 }
617
623 BOX2<Vec>& Merge( const BOX2<Vec>& aRect )
624 {
625 if( !m_init )
626 {
627 if( aRect.m_init )
628 {
629 m_Pos = aRect.GetPosition();
630 m_Size = aRect.GetSize();
631 m_init = true;
632 }
633
634 return *this;
635 }
636
637 Normalize(); // ensure width and height >= 0
638 BOX2<Vec> rect = aRect;
639 rect.Normalize(); // ensure width and height >= 0
640 Vec end = GetEnd();
641 Vec rect_end = rect.GetEnd();
642
643 // Change origin and size in order to contain the given rect
644 m_Pos.x = std::min( m_Pos.x, rect.m_Pos.x );
645 m_Pos.y = std::min( m_Pos.y, rect.m_Pos.y );
646 end.x = std::max( end.x, rect_end.x );
647 end.y = std::max( end.y, rect_end.y );
648 SetEnd( end );
649 return *this;
650 }
651
657 BOX2<Vec>& Merge( const Vec& aPoint )
658 {
659 if( !m_init )
660 {
661 m_Pos = aPoint;
662 m_Size = VECTOR2I( 0, 0 );
663 m_init = true;
664 return *this;
665 }
666
667 Normalize(); // ensure width and height >= 0
668
669 Vec end = GetEnd();
670
671 // Change origin and size in order to contain the given rectangle.
672 m_Pos.x = std::min( m_Pos.x, aPoint.x );
673 m_Pos.y = std::min( m_Pos.y, aPoint.y );
674 end.x = std::max( end.x, aPoint.x );
675 end.y = std::max( end.y, aPoint.y );
676 SetEnd( end );
677 return *this;
678 }
679
685 const BOX2<Vec> GetBoundingBoxRotated( const VECTOR2I& aRotCenter,
686 const EDA_ANGLE& aAngle ) const
687 {
688 VECTOR2I corners[4];
689
690 // Build the corners list
691 corners[0] = GetOrigin();
692 corners[2] = GetEnd();
693 corners[1].x = corners[0].x;
694 corners[1].y = corners[2].y;
695 corners[3].x = corners[2].x;
696 corners[3].y = corners[0].y;
697
698 // Rotate all corners, to find the bounding box
699 for( int ii = 0; ii < 4; ii++ )
700 RotatePoint( corners[ii], aRotCenter, aAngle );
701
702 // Find the corners bounding box
703 VECTOR2I start = corners[0];
704 VECTOR2I end = corners[0];
705
706 for( int ii = 1; ii < 4; ii++ )
707 {
708 start.x = std::min( start.x, corners[ii].x );
709 start.y = std::min( start.y, corners[ii].y );
710 end.x = std::max( end.x, corners[ii].x );
711 end.y = std::max( end.y, corners[ii].y );
712 }
713
714 BOX2<Vec> bbox;
715 bbox.SetOrigin( start );
716 bbox.SetEnd( end );
717
718 return bbox;
719 }
720
727 {
728 return (ecoord_type) GetWidth() * (ecoord_type) GetHeight();
729 }
730
737 {
738 return m_Size.EuclideanNorm();
739 }
740
741 ecoord_type SquaredDistance( const Vec& aP ) const
742 {
743 ecoord_type x2 = m_Pos.x + m_Size.x;
744 ecoord_type y2 = m_Pos.y + m_Size.y;
745 ecoord_type xdiff = std::max( aP.x < m_Pos.x ? m_Pos.x - aP.x : m_Pos.x - x2,
746 (ecoord_type) 0 );
747 ecoord_type ydiff = std::max( aP.y < m_Pos.y ? m_Pos.y - aP.y : m_Pos.y - y2,
748 (ecoord_type) 0 );
749 return xdiff * xdiff + ydiff * ydiff;
750 }
751
752 ecoord_type Distance( const Vec& aP ) const
753 {
754 return sqrt( SquaredDistance( aP ) );
755 }
756
764 {
765 ecoord_type s = 0;
766
767 if( aBox.m_Pos.x + aBox.m_Size.x < m_Pos.x )
768 {
769 ecoord_type d = aBox.m_Pos.x + aBox.m_Size.x - m_Pos.x;
770 s += d * d;
771 }
772 else if( aBox.m_Pos.x > m_Pos.x + m_Size.x )
773 {
774 ecoord_type d = aBox.m_Pos.x - m_Size.x - m_Pos.x;
775 s += d * d;
776 }
777
778 if( aBox.m_Pos.y + aBox.m_Size.y < m_Pos.y )
779 {
780 ecoord_type d = aBox.m_Pos.y + aBox.m_Size.y - m_Pos.y;
781 s += d * d;
782 }
783 else if( aBox.m_Pos.y > m_Pos.y + m_Size.y )
784 {
785 ecoord_type d = aBox.m_Pos.y - m_Size.y - m_Pos.y;
786 s += d * d;
787 }
788
789 return s;
790 }
791
798 ecoord_type Distance( const BOX2<Vec>& aBox ) const
799 {
800 return sqrt( SquaredDistance( aBox ) );
801 }
802
806 const Vec ClosestPointTo( const Vec& aPoint ) const
807 {
808 BOX2<Vec> me( *this );
809
810 me.Normalize(); // ensure size is >= 0
811
812 // Determine closest point to the circle centre within this rect
813 coord_type nx = alg::clamp( me.GetLeft(), aPoint.x, me.GetRight() );
814 coord_type ny = alg::clamp( me.GetTop(), aPoint.y, me.GetBottom() );
815
816 return Vec( nx, ny );
817 }
818
822 const Vec FarthestPointTo( const Vec& aPoint ) const
823 {
824 BOX2<Vec> me( *this );
825
826 me.Normalize(); // ensure size is >= 0
827
828 coord_type fx;
829 coord_type fy;
830
831 Vec center = me.GetCenter();
832
833 if( aPoint.x < center.x )
834 fx = me.GetRight();
835 else
836 fx = me.GetLeft();
837
838 if( aPoint.y < center.y )
839 fy = me.GetBottom();
840 else
841 fy = me.GetTop();
842
843 return Vec( fx, fy );
844 }
845
846 bool operator==( const BOX2<Vec>& aOther ) const
847 {
848 auto t1 ( *this );
849 auto t2 ( aOther );
850 t1.Normalize();
851 t2.Normalize();
852 return ( t1.m_Pos == t2.m_Pos && t1.m_Size == t2.m_Size );
853 }
854
855 bool operator!=( const BOX2<Vec>& aOther ) const
856 {
857 auto t1 ( *this );
858 auto t2 ( aOther );
859 t1.Normalize();
860 t2.Normalize();
861 return ( t1.m_Pos != t2.m_Pos || t1.m_Size != t2.m_Size );
862 }
863
864 bool IsValid() const
865 {
866 return m_init;
867 }
868
869private:
870 Vec m_Pos; // Rectangle Origin
871 SizeVec m_Size; // Rectangle Size
872
873 bool m_init; // Is the rectangle initialized
874};
875
876/* Default specializations */
879
880typedef std::optional<BOX2I> OPT_BOX2I;
881
882
883inline BOX2I BOX2ISafe( const BOX2D& aInput )
884{
885 constexpr double high = std::numeric_limits<int>::max();
886 constexpr double low = -std::numeric_limits<int>::max();
887
888 int left = (int) std::clamp( aInput.GetLeft(), low, high );
889 int top = (int) std::clamp( aInput.GetTop(), low, high );
890
891 int64_t right = (int64_t) std::clamp( aInput.GetRight(), low, high );
892 int64_t bottom = (int64_t) std::clamp( aInput.GetBottom(), low, high );
893
894 return BOX2I( VECTOR2I( left, top ), VECTOR2L( right - left, bottom - top ) );
895}
896
897
898inline BOX2I BOX2ISafe( const VECTOR2D& aPos, const VECTOR2D& aSize )
899{
900 constexpr double high = std::numeric_limits<int>::max();
901 constexpr double low = -std::numeric_limits<int>::max();
902
903 int left = (int) std::clamp( aPos.x, low, high );
904 int top = (int) std::clamp( aPos.y, low, high );
905
906 int64_t right = (int64_t) std::clamp( aPos.x + aSize.x, low, high );
907 int64_t bottom = (int64_t) std::clamp( aPos.y + aSize.y, low, high );
908
909 return BOX2I( VECTOR2I( left, top ), VECTOR2L( right - left, bottom - top ) );
910}
911
912
913template <typename S, std::enable_if_t<std::is_integral<S>::value, int> = 0>
914inline BOX2I BOX2ISafe( const VECTOR2I& aPos, const VECTOR2<S>& aSize )
915{
916 constexpr int64_t high = std::numeric_limits<int>::max();
917 constexpr int64_t low = -std::numeric_limits<int>::max();
918
919 int64_t ext_right = int64_t( aPos.x ) + aSize.x;
920 int64_t ext_bottom = int64_t( aPos.y ) + aSize.y;
921
922 int64_t right = std::clamp( ext_right, low, high );
923 int64_t bottom = std::clamp( ext_bottom, low, high );
924
925 return BOX2I( aPos, VECTOR2L( right - aPos.x, bottom - aPos.y ) );
926}
927
928
929#endif
BOX2< VECTOR2I > BOX2I
Definition: box2.h:877
std::optional< BOX2I > OPT_BOX2I
Definition: box2.h:880
BOX2I BOX2ISafe(const BOX2D &aInput)
Definition: box2.h:883
BOX2< VECTOR2D > BOX2D
Definition: box2.h:878
A 2D bounding box built on top of an origin point and size vector.
Definition: box2.h:44
ecoord_type SquaredDistance(const BOX2< Vec > &aBox) const
Return the square of the minimum distance between self and box aBox.
Definition: box2.h:763
void SetOrigin(const Vec &pos)
Definition: box2.h:227
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:136
bool m_init
Definition: box2.h:873
bool operator==(const BOX2< Vec > &aOther) const
Definition: box2.h:846
Vec::extended_type size_type
Definition: box2.h:47
void SetSize(const SizeVec &size)
Definition: box2.h:238
const Vec & GetPosition() const
Definition: box2.h:201
int GetSizeMax() const
Definition: box2.h:225
ecoord_type Distance(const BOX2< Vec > &aBox) const
Return the minimum distance between self and aBox.
Definition: box2.h:798
const Vec & GetOrigin() const
Definition: box2.h:200
void Offset(coord_type dx, coord_type dy)
Definition: box2.h:249
const std::string Format() const
Definition: box2.h:528
void SetMaximum()
Definition: box2.h:70
const SizeVec & GetSize() const
Definition: box2.h:196
bool Intersects(const BOX2< Vec > &aRect, const EDA_ANGLE &aRotation) const
Definition: box2.h:387
BOX2< Vec > Intersect(const BOX2< Vec > &aRect)
Definition: box2.h:330
ecoord_type Diagonal() const
Return the length of the diagonal of the rectangle.
Definition: box2.h:736
void SetSize(size_type w, size_type h)
Definition: box2.h:244
bool Intersects(const Vec &aPoint1, const Vec &aPoint2) const
Definition: box2.h:358
void SetHeight(size_type val)
Definition: box2.h:275
bool Contains(coord_type x, coord_type y) const
Definition: box2.h:184
size_type GetHeight() const
Definition: box2.h:205
Vec m_Pos
Definition: box2.h:870
void SetX(coord_type val)
Definition: box2.h:260
BOX2< Vec > & Inflate(int aDelta)
Inflate the rectangle horizontally and vertically by aDelta.
Definition: box2.h:612
BOX2< Vec > & Merge(const Vec &aPoint)
Modify the position and size of the rectangle in order to contain the given point.
Definition: box2.h:657
const Vec FarthestPointTo(const Vec &aPoint) const
Return the point in this rect that is farthest from the provided point.
Definition: box2.h:822
bool operator!=(const BOX2< Vec > &aOther) const
Definition: box2.h:855
const Vec GetCenter() const
Definition: box2.h:220
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:294
void SetWidth(size_type val)
Definition: box2.h:270
void SetY(coord_type val)
Definition: box2.h:265
bool Contains(const BOX2< Vec > &aRect) const
Definition: box2.h:191
Vec::extended_type ecoord_type
Definition: box2.h:48
bool IntersectsCircleEdge(const Vec &aCenter, const int aRadius, const int aWidth) const
Definition: box2.h:506
coord_type GetTop() const
Definition: box2.h:219
bool IntersectsCircle(const Vec &aCenter, const int aRadius) const
Definition: box2.h:487
VECTOR2< size_type > SizeVec
Definition: box2.h:49
size_type GetWidth() const
Definition: box2.h:204
coord_type GetY() const
Definition: box2.h:198
ecoord_type SquaredDistance(const Vec &aP) const
Definition: box2.h:741
void Offset(const Vec &offset)
Definition: box2.h:255
const Vec GetEnd() const
Definition: box2.h:202
void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition: box2.h:128
std::numeric_limits< coord_type > coord_limits
Definition: box2.h:50
SizeVec m_Size
Definition: box2.h:871
bool IsValid() const
Definition: box2.h:864
void SetEnd(const Vec &pos)
Definition: box2.h:285
const Vec ClosestPointTo(const Vec &aPoint) const
Return the point in this rect that is closest to the provided point.
Definition: box2.h:806
Vec::coord_type coord_type
Definition: box2.h:46
bool Contains(const Vec &aPoint) const
Definition: box2.h:158
void SetOrigin(coord_type x, coord_type y)
Definition: box2.h:233
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
ecoord_type Distance(const Vec &aP) const
Definition: box2.h:752
coord_type GetX() const
Definition: box2.h:197
Vec Centre() const
Definition: box2.h:87
coord_type GetRight() const
Definition: box2.h:207
ecoord_type GetArea() const
Return the area of the rectangle.
Definition: box2.h:726
BOX2(const Vec &aPos, const SizeVec &aSize=SizeVec(0, 0))
Definition: box2.h:58
coord_type GetLeft() const
Definition: box2.h:218
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:685
void Compute(const Container &aPointList)
Compute the bounding box from a given list of points.
Definition: box2.h:99
coord_type GetBottom() const
Definition: box2.h:212
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:280
BOX2()
Definition: box2.h:52
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:623
EDA_ANGLE Normalize()
Definition: eda_angle.h:255
Define a general 2D-vector/point.
Definition: vector2d.h:70
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:265
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:435
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:437
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_270
Definition: eda_angle.h:440
static constexpr EDA_ANGLE ANGLE_360
Definition: eda_angle.h:441
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:439
T clamp(T min, T value, T max)
Definition: kicad_algo.h:205
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:424
constexpr 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:228
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:106
VECTOR2< long long int > VECTOR2L
Definition: vector2d.h:603
VECTOR2< int > VECTOR2I
Definition: vector2d.h:602