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 inflateAxis( m_Pos.x, m_Size.x, dx );
556 inflateAxis( m_Pos.y, m_Size.y, dy );
557
558 return *this;
559 }
560
565 constexpr BOX2<Vec>& Inflate( coord_type aDelta )
566 {
567 Inflate( aDelta, aDelta );
568 return *this;
569 }
570
574 constexpr BOX2<Vec> GetInflated( coord_type aDx, coord_type aDy ) const
575 {
576 BOX2<Vec> ret( *this );
577 ret.Inflate( aDx, aDy );
578 return ret;
579 }
580
584 constexpr BOX2<Vec> GetInflated( coord_type aDelta ) const
585 {
586 return GetInflated( aDelta, aDelta );
587 }
588
594 constexpr BOX2<Vec>& Merge( const BOX2<Vec>& aRect )
595 {
596 if( !m_init )
597 {
598 if( aRect.m_init )
599 {
600 m_Pos = aRect.GetPosition();
601 m_Size = aRect.GetSize();
602 m_init = true;
603 }
604
605 return *this;
606 }
607
608 Normalize(); // ensure width and height >= 0
609 BOX2<Vec> rect = aRect;
610 rect.Normalize(); // ensure width and height >= 0
611 Vec end = GetEnd();
612 Vec rect_end = rect.GetEnd();
613
614 // Change origin and size in order to contain the given rect
615 m_Pos.x = std::min( m_Pos.x, rect.m_Pos.x );
616 m_Pos.y = std::min( m_Pos.y, rect.m_Pos.y );
617 end.x = std::max( end.x, rect_end.x );
618 end.y = std::max( end.y, rect_end.y );
619 SetEnd( end );
620 return *this;
621 }
622
628 constexpr BOX2<Vec>& Merge( const Vec& aPoint )
629 {
630 if( !m_init )
631 {
632 m_Pos = aPoint;
633 m_Size = VECTOR2I( 0, 0 );
634 m_init = true;
635 return *this;
636 }
637
638 Normalize(); // ensure width and height >= 0
639
640 Vec end = GetEnd();
641
642 // Change origin and size in order to contain the given rectangle.
643 m_Pos.x = std::min( m_Pos.x, aPoint.x );
644 m_Pos.y = std::min( m_Pos.y, aPoint.y );
645 end.x = std::max( end.x, aPoint.x );
646 end.y = std::max( end.y, aPoint.y );
647 SetEnd( end );
648 return *this;
649 }
650
656 const BOX2<Vec> GetBoundingBoxRotated( const VECTOR2I& aRotCenter,
657 const EDA_ANGLE& aAngle ) const
658 {
659 VECTOR2I corners[4];
660
661 // Build the corners list
662 corners[0] = GetOrigin();
663 corners[2] = GetEnd();
664 corners[1].x = corners[0].x;
665 corners[1].y = corners[2].y;
666 corners[3].x = corners[2].x;
667 corners[3].y = corners[0].y;
668
669 // Rotate all corners, to find the bounding box
670 for( int ii = 0; ii < 4; ii++ )
671 RotatePoint( corners[ii], aRotCenter, aAngle );
672
673 // Find the corners bounding box
674 VECTOR2I start = corners[0];
675 VECTOR2I end = corners[0];
676
677 for( int ii = 1; ii < 4; ii++ )
678 {
679 start.x = std::min( start.x, corners[ii].x );
680 start.y = std::min( start.y, corners[ii].y );
681 end.x = std::max( end.x, corners[ii].x );
682 end.y = std::max( end.y, corners[ii].y );
683 }
684
685 BOX2<Vec> bbox;
686 bbox.SetOrigin( start );
687 bbox.SetEnd( end );
688
689 return bbox;
690 }
691
697 constexpr ecoord_type GetArea() const
698 {
699 return (ecoord_type) GetWidth() * (ecoord_type) GetHeight();
700 }
701
708 {
709 return m_Size.EuclideanNorm();
710 }
711
717 constexpr ecoord_type SquaredDiagonal() const
718 {
719 return m_Size.SquaredEuclideanNorm();
720 }
721
722 constexpr ecoord_type SquaredDistance( const Vec& aP ) const
723 {
724 const ecoord_type x1 = std::min<ecoord_type>( m_Pos.x, ecoord_type( m_Pos.x ) + m_Size.x );
725 const ecoord_type x2 = std::max<ecoord_type>( m_Pos.x, ecoord_type( m_Pos.x ) + m_Size.x );
726 const ecoord_type y1 = std::min<ecoord_type>( m_Pos.y, ecoord_type( m_Pos.y ) + m_Size.y );
727 const ecoord_type y2 = std::max<ecoord_type>( m_Pos.y, ecoord_type( m_Pos.y ) + m_Size.y );
728
729 const ecoord_type xdiff = std::max<ecoord_type>( aP.x < x1 ? x1 - aP.x : ecoord_type( aP.x ) - x2, 0 );
730 const ecoord_type ydiff = std::max<ecoord_type>( aP.y < y1 ? y1 - aP.y : ecoord_type( aP.y ) - y2, 0 );
731
732 return xdiff * xdiff + ydiff * ydiff;
733 }
734
735 ecoord_type Distance( const Vec& aP ) const
736 {
737 const double dist = std::sqrt( static_cast<double>( SquaredDistance( aP ) ) );
738
739 if constexpr( std::is_floating_point<ecoord_type>() )
740 return static_cast<ecoord_type>( dist );
741 else
742 return KiROUND<double, ecoord_type>( dist );
743 }
744
751 constexpr ecoord_type SquaredDistance( const BOX2<Vec>& aBox ) const
752 {
753 ecoord_type s = 0;
754
755 if( aBox.m_Pos.x + aBox.m_Size.x < m_Pos.x )
756 {
757 ecoord_type d = aBox.m_Pos.x + aBox.m_Size.x - m_Pos.x;
758 s += d * d;
759 }
760 else if( aBox.m_Pos.x > m_Pos.x + m_Size.x )
761 {
762 ecoord_type d = aBox.m_Pos.x - m_Size.x - m_Pos.x;
763 s += d * d;
764 }
765
766 if( aBox.m_Pos.y + aBox.m_Size.y < m_Pos.y )
767 {
768 ecoord_type d = aBox.m_Pos.y + aBox.m_Size.y - m_Pos.y;
769 s += d * d;
770 }
771 else if( aBox.m_Pos.y > m_Pos.y + m_Size.y )
772 {
773 ecoord_type d = aBox.m_Pos.y - m_Size.y - m_Pos.y;
774 s += d * d;
775 }
776
777 return s;
778 }
779
786 ecoord_type Distance( const BOX2<Vec>& aBox ) const
787 {
788 const double dist = std::sqrt( static_cast<double>( SquaredDistance( aBox ) ) );
789
790 if constexpr( std::is_floating_point<ecoord_type>() )
791 return static_cast<ecoord_type>( dist );
792 else
793 return KiROUND<double, ecoord_type>( dist );
794 }
795
799 constexpr Vec NearestPoint( const Vec& aPoint ) const
800 {
801 BOX2<Vec> me( *this );
802
803 me.Normalize(); // ensure size is >= 0
804
805 // Determine closest point to the circle centre within this rect
806 const coord_type nx = std::clamp( aPoint.x, me.GetLeft(), me.GetRight() );
807 const coord_type ny = std::clamp( aPoint.y, me.GetTop(), me.GetBottom() );
808
809 return Vec( nx, ny );
810 }
811
815 constexpr Vec FarthestPointTo( const Vec& aPoint ) const
816 {
817 BOX2<Vec> me( *this );
818
819 me.Normalize(); // ensure size is >= 0
820
821 coord_type fx;
822 coord_type fy;
823
824 Vec center = me.GetCenter();
825
826 if( aPoint.x < center.x )
827 fx = me.GetRight();
828 else
829 fx = me.GetLeft();
830
831 if( aPoint.y < center.y )
832 fy = me.GetBottom();
833 else
834 fy = me.GetTop();
835
836 return Vec( fx, fy );
837 }
838
839 constexpr bool operator==( const BOX2<Vec>& aOther ) const
840 {
841 auto t1 ( *this );
842 auto t2 ( aOther );
843 t1.Normalize();
844 t2.Normalize();
845 return ( t1.m_Pos == t2.m_Pos && t1.m_Size == t2.m_Size );
846 }
847
848 constexpr bool operator!=( const BOX2<Vec>& aOther ) const
849 {
850 auto t1 ( *this );
851 auto t2 ( aOther );
852 t1.Normalize();
853 t2.Normalize();
854 return ( t1.m_Pos != t2.m_Pos || t1.m_Size != t2.m_Size );
855 }
856
857 constexpr bool IsValid() const
858 {
859 return m_init;
860 }
861
862private:
863 // Widened so that sentinel deltas cannot wrap, results saturate outward to keep the original region covered
864 static constexpr void inflateAxis( coord_type& aPos, size_type& aSize, coord_type aDelta )
865 {
866 const ecoord_type pos = aPos;
867 const ecoord_type delta = aDelta;
868 const ecoord_type lowLimit = coord_limits::lowest();
869 const ecoord_type highLimit = coord_limits::max();
870
871 if( aSize >= 0 )
872 {
873 if( aSize < -2 * delta )
874 {
875 // Don't allow deflate to eat more width than we have,
876 aPos = KiCheckedCast<ecoord_type, coord_type>( pos + aSize / 2 );
877 aSize = 0;
878 }
879 else
880 {
881 const ecoord_type lo = std::clamp<ecoord_type>( pos - delta, lowLimit, highLimit );
882 const ecoord_type hi = std::clamp<ecoord_type>( pos + aSize + delta, lowLimit, highLimit );
883
884 aPos = static_cast<coord_type>( lo );
885 aSize = hi - lo;
886 }
887 }
888 else
889 {
890 if( aSize > 2 * delta )
891 {
892 aPos = KiCheckedCast<ecoord_type, coord_type>( pos - aSize / 2 );
893 aSize = 0;
894 }
895 else
896 {
897 // Negative size, pos is the high edge so inflating moves it up and the low edge down
898 const ecoord_type hi = std::clamp<ecoord_type>( pos + delta, lowLimit, highLimit );
899 const ecoord_type lo = std::clamp<ecoord_type>( pos + aSize - delta, lowLimit, highLimit );
900
901 aPos = static_cast<coord_type>( hi );
902 aSize = lo - hi;
903 }
904 }
905 }
906
907 Vec m_Pos; // Rectangle Origin
908 SizeVec m_Size; // Rectangle Size
909
910 bool m_init; // Is the rectangle initialized
911};
912
913/* Default specializations */
917
918typedef std::optional<BOX2I> OPT_BOX2I;
919
920
921inline constexpr BOX2I BOX2ISafe( const BOX2D& aInput )
922{
923 constexpr double high = std::numeric_limits<int>::max();
924 constexpr double low = -std::numeric_limits<int>::max();
925
926 int left = (int) std::clamp( aInput.GetLeft(), low, high );
927 int top = (int) std::clamp( aInput.GetTop(), low, high );
928
929 int64_t right = (int64_t) std::clamp( aInput.GetRight(), low, high );
930 int64_t bottom = (int64_t) std::clamp( aInput.GetBottom(), low, high );
931
932 return BOX2I( VECTOR2I( left, top ), VECTOR2L( right - left, bottom - top ) );
933}
934
935
940template <typename Vec>
941inline constexpr bool IsBOX2Safe( const BOX2<Vec>& aInput )
942{
943 constexpr double high = std::numeric_limits<int>::max();
944 constexpr double low = -std::numeric_limits<int>::max();
945
946 return ( aInput.GetLeft() >= low && aInput.GetTop() >= low &&
947 aInput.GetRight() <= high && aInput.GetBottom() <= high );
948}
949
950
951inline constexpr BOX2I BOX2ISafe( const VECTOR2D& aPos, const VECTOR2D& aSize )
952{
953 constexpr double high = std::numeric_limits<int>::max();
954 constexpr double low = -std::numeric_limits<int>::max();
955
956 int left = (int) std::clamp( aPos.x, low, high );
957 int top = (int) std::clamp( aPos.y, low, high );
958
959 int64_t right = (int64_t) std::clamp( aPos.x + aSize.x, low, high );
960 int64_t bottom = (int64_t) std::clamp( aPos.y + aSize.y, low, high );
961
962 return BOX2I( VECTOR2I( left, top ), VECTOR2L( right - left, bottom - top ) );
963}
964
965
966template <typename S, std::enable_if_t<std::is_integral<S>::value, int> = 0>
967inline constexpr BOX2I BOX2ISafe( const VECTOR2I& aPos, const VECTOR2<S>& aSize )
968{
969 constexpr int64_t high = std::numeric_limits<int>::max();
970 constexpr int64_t low = -std::numeric_limits<int>::max();
971
972 int64_t ext_right = int64_t( aPos.x ) + aSize.x;
973 int64_t ext_bottom = int64_t( aPos.y ) + aSize.y;
974
975 int64_t right = std::clamp( ext_right, low, high );
976 int64_t bottom = std::clamp( ext_bottom, low, high );
977
978 return BOX2I( aPos, VECTOR2L( right - aPos.x, bottom - aPos.y ) );
979}
980
981/* KiROUND specialization for double -> int boxes */
982inline constexpr BOX2I KiROUND( const BOX2D& aBoxD )
983{
984 return BOX2I( KiROUND( aBoxD.GetOrigin() ), KiROUND( aBoxD.GetSize() ) );
985}
986
987#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:941
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition box2.h:921
BOX2< VECTOR2L > BOX2L
Definition box2.h:916
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
std::optional< BOX2I > OPT_BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
BOX2< VECTOR2D > BOX2D
Definition box2.h:915
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:751
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:839
ecoord_type Distance(const BOX2< Vec > &aBox) const
Return the minimum distance between self and aBox.
Definition box2.h:786
static constexpr void inflateAxis(coord_type &aPos, size_type &aSize, coord_type aDelta)
Definition box2.h:864
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:565
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:717
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:799
ecoord_type Diagonal() const
Return the length of the diagonal of the rectangle.
Definition box2.h:707
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:907
constexpr BOX2()
Definition box2.h:49
constexpr bool operator!=(const BOX2< Vec > &aOther) const
Definition box2.h:848
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:594
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:697
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:908
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:584
ecoord_type Distance(const Vec &aP) const
Definition box2.h:735
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:722
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:574
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:857
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:656
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:628
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:815
EDA_ANGLE Normalize()
Definition eda_angle.h:228
Define a general 2D-vector/point.
Definition vector2d.h:67
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:450
@ DEGREES_T
Definition eda_angle.h:30
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:453
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:454
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:452
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
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:227
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:105
constexpr ret_type KiCheckedCast(in_type v)
Perform a cast between numerical types.
Definition util.h:66
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:709