mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-04-20 00:21:31 +00:00
Multichannel: split out some geometric routines
Putting them somewhere in the geom utils means they can be reused, and also tested if needed.
This commit is contained in:
parent
6a96c16c2c
commit
df933df416
libs/kimath
pcbnew/tools
@ -75,6 +75,11 @@ OPT_VECTOR2I GetSharedEndpoint( const SEG& aSegA, const SEG& aSegB );
|
||||
*/
|
||||
std::array<SEG, 4> BoxToSegs( const BOX2I& aBox );
|
||||
|
||||
/**
|
||||
* Add the 4 corners of a BOX2I to a vector.
|
||||
*/
|
||||
void CollectBoxCorners( const BOX2I& aBox, std::vector<VECTOR2I>& aCorners );
|
||||
|
||||
/**
|
||||
* Get the segments of a box that are in the given direction.
|
||||
*
|
||||
@ -142,4 +147,19 @@ VECTOR2I GetPoint( const SHAPE_RECT& aRect, DIRECTION_45::Directions aDir, int a
|
||||
*/
|
||||
std::vector<TYPED_POINT2I> GetCircleKeyPoints( const CIRCLE& aCircle, bool aIncludeCenter );
|
||||
|
||||
|
||||
/*
|
||||
* Take a polygon and 'rectify' it, so that all sides are H/V.
|
||||
*
|
||||
* The entire original polygon is contained within the new one.
|
||||
* The new polygon will pass though each original corner,
|
||||
* but it can have additional corners, or corners can be simplified away.
|
||||
*
|
||||
* E.g.:
|
||||
* ____ _______
|
||||
* / \___ -> | |___
|
||||
* |________\ |_________|
|
||||
*/
|
||||
SHAPE_LINE_CHAIN RectifyPolygon( const SHAPE_LINE_CHAIN& aPoly );
|
||||
|
||||
} // namespace KIGEOM
|
@ -80,6 +80,15 @@ std::array<SEG, 4> KIGEOM::BoxToSegs( const BOX2I& aBox )
|
||||
}
|
||||
|
||||
|
||||
void KIGEOM::CollectBoxCorners( const BOX2I& aBox, std::vector<VECTOR2I>& aCorners )
|
||||
{
|
||||
aCorners.push_back( { aBox.GetLeft(), aBox.GetTop() } );
|
||||
aCorners.push_back( { aBox.GetRight(), aBox.GetTop() } );
|
||||
aCorners.push_back( { aBox.GetRight(), aBox.GetBottom() } );
|
||||
aCorners.push_back( { aBox.GetLeft(), aBox.GetBottom() } );
|
||||
}
|
||||
|
||||
|
||||
std::vector<SEG> KIGEOM::GetSegsInDirection( const BOX2I& aBox, DIRECTION_45::Directions aDir )
|
||||
{
|
||||
// clang-format off
|
||||
@ -332,4 +341,38 @@ std::vector<TYPED_POINT2I> KIGEOM::GetCircleKeyPoints( const CIRCLE& aCircle, bo
|
||||
}
|
||||
|
||||
return pts;
|
||||
}
|
||||
|
||||
|
||||
SHAPE_LINE_CHAIN KIGEOM::RectifyPolygon( const SHAPE_LINE_CHAIN& aPoly )
|
||||
{
|
||||
SHAPE_LINE_CHAIN raOutline;
|
||||
|
||||
const auto handleSegment = [&]( const SEG& aSeg )
|
||||
{
|
||||
const VECTOR2I p0( aSeg.A.x, aSeg.B.y );
|
||||
const VECTOR2I p1( aSeg.B.x, aSeg.A.y );
|
||||
|
||||
raOutline.Append( aSeg.A );
|
||||
if( !aPoly.PointInside( p0 ) )
|
||||
raOutline.Append( p0 );
|
||||
else
|
||||
raOutline.Append( p1 );
|
||||
};
|
||||
|
||||
for( int i = 0; i < aPoly.SegmentCount(); i++ )
|
||||
{
|
||||
handleSegment( aPoly.CSegment( i ) );
|
||||
}
|
||||
|
||||
// Manually handle the last segment if not closed
|
||||
if( !aPoly.IsClosed() )
|
||||
{
|
||||
handleSegment( SEG( aPoly.CPoint( -1 ), aPoly.CPoint( 0 ) ) );
|
||||
}
|
||||
|
||||
raOutline.SetClosed( true );
|
||||
raOutline.Simplify();
|
||||
|
||||
return raOutline;
|
||||
}
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include <zone.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
#include <geometry/shape_utils.h>
|
||||
#include <pcb_group.h>
|
||||
#include <connectivity/connectivity_data.h>
|
||||
#include <connectivity/topo_match.h>
|
||||
@ -168,43 +169,22 @@ MULTICHANNEL_TOOL::queryComponentsInComponentClass( const wxString& aComponentCl
|
||||
const SHAPE_LINE_CHAIN MULTICHANNEL_TOOL::buildRAOutline( std::set<FOOTPRINT*>& aFootprints,
|
||||
int aMargin )
|
||||
{
|
||||
std::vector<VECTOR2I> bbCorners, hullVertices;
|
||||
std::vector<VECTOR2I> bbCorners;
|
||||
bbCorners.reserve( aFootprints.size() * 4 );
|
||||
|
||||
for( auto fp : aFootprints )
|
||||
{
|
||||
auto bb = fp->GetBoundingBox( false );
|
||||
bb.Inflate( aMargin );
|
||||
|
||||
bbCorners.push_back( VECTOR2I( bb.GetX(), bb.GetY() ) );
|
||||
bbCorners.push_back( VECTOR2I( bb.GetX() + bb.GetWidth(), bb.GetY() ) );
|
||||
bbCorners.push_back( VECTOR2I( bb.GetX() + bb.GetWidth(), bb.GetY() + bb.GetHeight() ) );
|
||||
bbCorners.push_back( VECTOR2I( bb.GetX(), bb.GetY() + bb.GetHeight() ) );
|
||||
const BOX2I bb = fp->GetBoundingBox( false ).GetInflated( aMargin );
|
||||
KIGEOM::CollectBoxCorners( bb, bbCorners );
|
||||
}
|
||||
|
||||
std::vector<VECTOR2I> hullVertices;
|
||||
BuildConvexHull( hullVertices, bbCorners );
|
||||
|
||||
SHAPE_LINE_CHAIN hull( hullVertices );
|
||||
SHAPE_LINE_CHAIN raOutline;
|
||||
|
||||
// make the newly computed convex hull use only 90 degree segments
|
||||
hull.SetClosed( true );
|
||||
for( int i = 0; i < hull.SegmentCount(); i++ )
|
||||
{
|
||||
const auto& seg = hull.CSegment( i );
|
||||
const VECTOR2I p0( seg.A.x, seg.B.y );
|
||||
const VECTOR2I p1( seg.B.x, seg.A.y );
|
||||
|
||||
raOutline.Append( seg.A );
|
||||
if( !hull.PointInside( p0 ) )
|
||||
raOutline.Append( p0 );
|
||||
else
|
||||
raOutline.Append( p1 );
|
||||
}
|
||||
|
||||
raOutline.SetClosed( true );
|
||||
raOutline.Simplify();
|
||||
|
||||
return raOutline;
|
||||
// Make the newly computed convex hull use only 90 degree segments
|
||||
return KIGEOM::RectifyPolygon( hull );
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user