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