Optimize ratsnest line endings for zones.

This commit is contained in:
Jeff Young 2022-09-30 19:04:54 +00:00
parent 01572c0f7d
commit f095453d3e
3 changed files with 138 additions and 2 deletions

View File

@ -250,6 +250,9 @@ public:
virtual int AnchorCount() const; virtual int AnchorCount() const;
virtual const VECTOR2I GetAnchor( int n ) const; virtual const VECTOR2I GetAnchor( int n ) const;
int GetAnchorItemCount() const { return m_anchors.size(); }
std::shared_ptr<CN_ANCHOR> GetAnchorItem( int n ) const { return m_anchors[n]; }
int Net() const int Net() const
{ {
return ( !m_parent || !m_valid ) ? -1 : m_parent->GetNetCode(); return ( !m_parent || !m_valid ) ? -1 : m_parent->GetNetCode();
@ -343,6 +346,20 @@ public:
virtual int AnchorCount() const override; virtual int AnchorCount() const override;
virtual const VECTOR2I GetAnchor( int n ) const override; virtual const VECTOR2I GetAnchor( int n ) const override;
const SHAPE_LINE_CHAIN& GetOutline() const
{
return m_triangulatedPoly->Outline( m_subpolyIndex );
}
VECTOR2I ClosestPoint( const VECTOR2I aPt )
{
VECTOR2I closest;
m_triangulatedPoly->SquaredDistanceToPolygon( aPt, m_subpolyIndex, &closest );
return closest;
}
bool Collide( SHAPE* aRefShape ) const bool Collide( SHAPE* aRefShape ) const
{ {
BOX2I bbox = aRefShape->BBox(); BOX2I bbox = aRefShape->BBox();
@ -368,7 +385,6 @@ public:
} }
private: private:
std::vector<VECTOR2I> m_testOutlinePoints;
int m_subpolyIndex; int m_subpolyIndex;
PCB_LAYER_ID m_layer; PCB_LAYER_ID m_layer;
std::shared_ptr<SHAPE_POLY_SET> m_triangulatedPoly; std::shared_ptr<SHAPE_POLY_SET> m_triangulatedPoly;

View File

@ -328,11 +328,127 @@ void RN_NET::compute()
} }
void RN_NET::optimizeRNEdges()
{
auto findZoneAnchor =
[&]( const VECTOR2I& aPos, const LSET& aLayerSet,
const std::shared_ptr<CN_ANCHOR> aAnchor )
{
SEG::ecoord closest_dist_sq = ( aAnchor->Pos() - aPos ).SquaredEuclideanNorm();
VECTOR2I closest_pt;
CN_ITEM* closest_item = nullptr;
for( CN_ITEM* item : aAnchor->Item()->ConnectedItems() )
{
CN_ZONE_LAYER* zoneLayer = dynamic_cast<CN_ZONE_LAYER*>( item );
if( zoneLayer && aLayerSet.test( zoneLayer->Layer() ) )
{
const std::vector<VECTOR2I>& pts = zoneLayer->GetOutline().CPoints();
for( VECTOR2I pt : pts )
{
SEG::ecoord dist_sq = ( pt - aPos ).SquaredEuclideanNorm();
if( dist_sq < closest_dist_sq )
{
closest_pt = pt;
closest_item = zoneLayer;
closest_dist_sq = dist_sq;
}
}
}
}
if( closest_item )
{
closest_item->AddAnchor( closest_pt );
return closest_item->GetAnchorItem( closest_item->GetAnchorItemCount() - 1 );
}
return aAnchor;
};
auto findZoneToZoneAnchors =
[&]( std::shared_ptr<CN_ANCHOR>& a, std::shared_ptr<CN_ANCHOR>& b )
{
for( CN_ITEM* itemA : a->Item()->ConnectedItems() )
{
CN_ZONE_LAYER* zoneLayerA = dynamic_cast<CN_ZONE_LAYER*>( itemA );
if( !zoneLayerA )
continue;
for( CN_ITEM* itemB : b->Item()->ConnectedItems() )
{
CN_ZONE_LAYER* zoneLayerB = dynamic_cast<CN_ZONE_LAYER*>( itemB );
if( zoneLayerB && zoneLayerB->Layer() == zoneLayerA->Layer() )
{
// Process the first matching layer. We don't really care if it's
// the "best" layer or not, as anything will be better than the
// original anchors (which are connected to the zone and so certainly
// don't look like they should have ratsnest lines coming off them).
VECTOR2I startA = zoneLayerA->GetOutline().GetPoint( 0 );
VECTOR2I startB = zoneLayerB->GetOutline().GetPoint( 0 );
const SHAPE* shapeA = &zoneLayerA->GetOutline();
const SHAPE* shapeB = &zoneLayerB->GetOutline();
int startDist = ( startA - startB ).EuclideanNorm();
VECTOR2I ptA;
shapeA->Collide( shapeB, startDist + 10, nullptr, &ptA );
zoneLayerA->AddAnchor( ptA );
a = zoneLayerA->GetAnchorItem( zoneLayerA->GetAnchorItemCount() - 1 );
VECTOR2I ptB;
shapeB->Collide( shapeA, startDist + 10, nullptr, &ptB );
zoneLayerB->AddAnchor( ptB );
b = zoneLayerB->GetAnchorItem( zoneLayerB->GetAnchorItemCount() - 1 );
return;
}
}
}
};
for( CN_EDGE& edge : m_rnEdges )
{
std::shared_ptr<CN_ANCHOR> source = edge.GetSourceNode();
std::shared_ptr<CN_ANCHOR> target = edge.GetTargetNode();
if( source->ConnectedItemsCount() == 0 )
{
edge.SetTargetNode( findZoneAnchor( source->Pos(), source->Parent()->GetLayerSet(),
target ) );
}
else if( target->ConnectedItemsCount() == 0 )
{
edge.SetSourceNode( findZoneAnchor( target->Pos(), target->Parent()->GetLayerSet(),
source ) );
}
else
{
findZoneToZoneAnchors( source, target );
edge.SetSourceNode( source );
edge.SetTargetNode( target );
}
}
}
void RN_NET::Update() void RN_NET::Update()
{ {
compute(); compute();
#ifdef PROFILE
PROF_TIMER cnt( "optimize" );
#endif
optimizeRNEdges();
#ifdef PROFILE
cnt.Show();
#endif
m_dirty = false; m_dirty = false;
} }
@ -451,4 +567,3 @@ bool RN_NET::NearestBicoloredPair( const RN_NET& aOtherNet, VECTOR2I* aPos1, VEC
return rv; return rv;
} }

View File

@ -99,6 +99,11 @@ protected:
///< Compute the minimum spanning tree using Kruskal's algorithm ///< Compute the minimum spanning tree using Kruskal's algorithm
void kruskalMST( const std::vector<CN_EDGE> &aEdges ); void kruskalMST( const std::vector<CN_EDGE> &aEdges );
///< Find optimal ends of RNEdges. The MST will have found the closest anchors, but when
///< zones are involved we might have points closer than the anchors.
void optimizeRNEdges();
protected:
///< Vector of nodes ///< Vector of nodes
std::multiset<std::shared_ptr<CN_ANCHOR>, CN_PTR_CMP> m_nodes; std::multiset<std::shared_ptr<CN_ANCHOR>, CN_PTR_CMP> m_nodes;