Teardrops: handle arcs in tracks.

Fixes #13858
https://gitlab.com/kicad/code/kicad/issues/13858
This commit is contained in:
jean-pierre charras 2023-02-19 14:44:37 +01:00
parent 30a49462fe
commit 3a11d90d92
3 changed files with 79 additions and 15 deletions

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2021 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2021 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -117,7 +117,7 @@ int TEARDROP_MANAGER::SetTeardrops( BOARD_COMMIT* aCommitter, bool aFollowTracks
// Build the track list (only straight lines) // Build the track list (only straight lines)
for( PCB_TRACK* track: m_board->Tracks() ) for( PCB_TRACK* track: m_board->Tracks() )
{ {
if( track->Type() == PCB_TRACE_T ) if( track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T)
{ {
int netcode = track->GetNetCode(); int netcode = track->GetNetCode();
int layer = track->GetLayer(); int layer = track->GetLayer();
@ -132,7 +132,7 @@ int TEARDROP_MANAGER::SetTeardrops( BOARD_COMMIT* aCommitter, bool aFollowTracks
for( PCB_TRACK* track : m_board->Tracks() ) for( PCB_TRACK* track : m_board->Tracks() )
{ {
if( track->Type() != PCB_TRACE_T ) if( ! (track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T ) )
continue; continue;
// Search for a padvia connected to track, with one end inside and one end outside // Search for a padvia connected to track, with one end inside and one end outside
@ -284,7 +284,7 @@ int TEARDROP_MANAGER::addTeardropsOnTracks( BOARD_COMMIT* aCommitter )
// Build the track list (only straight lines) // Build the track list (only straight lines)
for( PCB_TRACK* track: m_board->Tracks() ) for( PCB_TRACK* track: m_board->Tracks() )
{ {
if( track->Type() == PCB_TRACE_T ) if( track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T )
{ {
int netcode = track->GetNetCode(); int netcode = track->GetNetCode();
int layer = track->GetLayer(); int layer = track->GetLayer();

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2021 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2021 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -183,7 +183,7 @@ private:
/** /**
* Compute the 2 points on pad/via of the teardrop shape * Compute the 2 points on pad/via of the teardrop shape
* @return false if these 2 points are not found * @return false if these 2 points are not found
* @param aTrack is the reference track included in teardrop * @param aLayer is the layer for the teardrop
* @param aViaPad is the teardrop anchor * @param aViaPad is the teardrop anchor
* teardrop height = aViaPad size * aHeightRatio * teardrop height = aViaPad size * aHeightRatio
* @param aPts is the buffer that contains initial and final teardrop polygonal shape * @param aPts is the buffer that contains initial and final teardrop polygonal shape
@ -194,7 +194,7 @@ private:
* m_heightRatio is the factor to calculate the aViaPad teardrop size * m_heightRatio is the factor to calculate the aViaPad teardrop size
*/ */
bool ComputePointsOnPadVia( TEARDROP_PARAMETERS* aCurrParams, bool ComputePointsOnPadVia( TEARDROP_PARAMETERS* aCurrParams,
PCB_TRACK* aTrack, VIAPAD& aViaPad, PCB_LAYER_ID aLayer, VIAPAD& aViaPad,
std::vector<VECTOR2I>& aPts ) const; std::vector<VECTOR2I>& aPts ) const;
/** /**

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2021 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2021 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -401,7 +401,7 @@ void TEARDROP_MANAGER::computeCurvedForRectShape( TEARDROP_PARAMETERS* aCurrPar
bool TEARDROP_MANAGER::ComputePointsOnPadVia( TEARDROP_PARAMETERS* aCurrParams, bool TEARDROP_MANAGER::ComputePointsOnPadVia( TEARDROP_PARAMETERS* aCurrParams,
PCB_TRACK* aTrack, PCB_LAYER_ID aLayer,
VIAPAD& aViaPad, VIAPAD& aViaPad,
std::vector<VECTOR2I>& aPts ) const std::vector<VECTOR2I>& aPts ) const
{ {
@ -441,7 +441,7 @@ bool TEARDROP_MANAGER::ComputePointsOnPadVia( TEARDROP_PARAMETERS* aCurrParams,
force_clip_shape = true; force_clip_shape = true;
preferred_height = aViaPad.m_Width * aCurrParams->m_HeightRatio; preferred_height = aViaPad.m_Width * aCurrParams->m_HeightRatio;
pad->TransformShapeToPolygon( c_buffer, aTrack->GetLayer(), 0, ARC_LOW_DEF, ERROR_INSIDE ); pad->TransformShapeToPolygon( c_buffer, aLayer, 0, ARC_LOW_DEF, ERROR_INSIDE );
} }
// Clip the pad/via shape to match the m_TdMaxHeight constraint, and for // Clip the pad/via shape to match the m_TdMaxHeight constraint, and for
@ -593,8 +593,8 @@ bool TEARDROP_MANAGER::findAnchorPointsOnTrack( TEARDROP_PARAMETERS* aCurrParams
TRACK_BUFFER& aTrackLookupList ) const TRACK_BUFFER& aTrackLookupList ) const
{ {
bool found = true; bool found = true;
VECTOR2I start = aTrack->GetStart(); VECTOR2I start = aTrack->GetStart(); // the anchor point on the track, inside teardrop
VECTOR2I end = aTrack->GetEnd(); VECTOR2I end = aTrack->GetEnd(); // the anchor point on the track, outside teardrop
int radius = aViaPad.m_Width / 2; int radius = aViaPad.m_Width / 2;
// Requested length of the teardrop: // Requested length of the teardrop:
@ -604,11 +604,13 @@ bool TEARDROP_MANAGER::findAnchorPointsOnTrack( TEARDROP_PARAMETERS* aCurrParams
targetLength = std::min( aCurrParams->m_TdMaxLen, targetLength ); targetLength = std::min( aCurrParams->m_TdMaxLen, targetLength );
int actualTdLen; // The actual teardrop length, limited by the available track length int actualTdLen; // The actual teardrop length, limited by the available track length
bool need_swap = false; // true if the start and end points of the current track are swapped
// ensure that start is at the via/pad end // ensure that start is at the via/pad end
if( SEG( end, aViaPad.m_Pos ).Length() < radius ) if( SEG( end, aViaPad.m_Pos ).Length() < radius )
{ {
std::swap( start, end ); std::swap( start, end );
need_swap = true;
} }
SHAPE_POLY_SET shapebuffer; SHAPE_POLY_SET shapebuffer;
@ -639,9 +641,10 @@ bool TEARDROP_MANAGER::findAnchorPointsOnTrack( TEARDROP_PARAMETERS* aCurrParams
return false; return false;
VECTOR2I intersect = pts[0].p; VECTOR2I intersect = pts[0].p;
start.x = intersect.x; start = intersect;
start.y = intersect.y;
actualTdLen = std::min( targetLength, SEG( start, end ).Length() ); actualTdLen = std::min( targetLength, SEG( start, end ).Length() );
VECTOR2I ref_lenght_point = start; // the reference point of actualTdLen
// If the first track is too short to allow a teardrop having the requested length // If the first track is too short to allow a teardrop having the requested length
// explore the connected track(s) // explore the connected track(s)
@ -664,17 +667,78 @@ bool TEARDROP_MANAGER::findAnchorPointsOnTrack( TEARDROP_PARAMETERS* aCurrParams
aTrack = connected_track; aTrack = connected_track;
end = connected_track->GetEnd(); end = connected_track->GetEnd();
start = connected_track->GetStart(); start = connected_track->GetStart();
need_swap = false;
if( matchType != STARTPOINT ) if( matchType != STARTPOINT )
{
std::swap( start, end ); std::swap( start, end );
need_swap = true;
}
// If we do not want to explore more than one connected track, stop search here // If we do not want to explore more than one connected track, stop search here
break; break;
} }
} }
// if aTrack is an arc, find the best teardrop end point on the arc
// It is currently on the segment from arc start point to arc end point,
// therefore not really on the arc, because we have used only the track end points.
if( aTrack->Type() == PCB_ARC_T )
{
// To find the best start and end points to build the teardrop shape, we convert
// the arc to segments, and search for the segment havig its start point at a dist
// < actualTdLen, and its end point at adist > actualTdLen:
SHAPE_ARC arc( aTrack->GetStart(), static_cast<PCB_ARC*>( aTrack )->GetMid(),
aTrack->GetEnd(), aTrack->GetWidth() );
if( need_swap )
arc.Reverse();
SHAPE_LINE_CHAIN poly = arc.ConvertToPolyline();
// Now, find the segment of the arc at a distance < actualTdLen from ref_lenght_point.
// We just search for the first segment (starting from the farest segment) with its
// start point at a distance < actualTdLen dist
// This is basic, but it is probably enough.
if( poly.PointCount() > 2 )
{
// Note: the first point is inside or near the pad/via shape
// The last point is outside and the farest from the ref_lenght_point
// So we explore segments from the last to the first
for( int ii = poly.PointCount()-1; ii >= 0 ; ii-- )
{
int dist_from_start = ( poly.CPoint( ii ) - ref_lenght_point ).EuclideanNorm();
// The first segment at a distance of the reference point < actualTdLen is OK
if( dist_from_start < actualTdLen )
{
start = poly.CPoint( ii );
if( ii < poly.PointCount()-1 )
end = poly.CPoint( ii+1 );
// actualTdLen is the distance between start (the segment start point)
// and the point on track of the teardrop.
// This is the difference between the initial actualTdLen value and the
// distance between start and ref_lenght_point.
actualTdLen -= (start - ref_lenght_point).EuclideanNorm();
if( actualTdLen < 0 )
actualTdLen = 0;
break;
}
}
}
}
// aStartPoint and aEndPoint will define later a segment to build the 2 anchors points
// of the teardrop on the aTrack shape.
// they are the end point of aTrack if aTrack is a segment,
// or a small segment on aTrack if aTrack is an ARC
aStartPoint = start; aStartPoint = start;
aEndPoint = end; aEndPoint = end;
*aEffectiveTeardropLen = actualTdLen; *aEffectiveTeardropLen = actualTdLen;
return found; return found;
} }
@ -733,7 +797,7 @@ bool TEARDROP_MANAGER::computeTeardropPolygonPoints( TEARDROP_PARAMETERS* aCurrP
VECTOR2I pointC, pointE; // Point on PADVIA outlines VECTOR2I pointC, pointE; // Point on PADVIA outlines
std::vector<VECTOR2I> pts = {pointA, pointB, pointC, pointD, pointE}; std::vector<VECTOR2I> pts = {pointA, pointB, pointC, pointD, pointE};
ComputePointsOnPadVia( aCurrParams, aTrack, aViaPad, pts ); ComputePointsOnPadVia( aCurrParams, aTrack->GetLayer(), aViaPad, pts );
if( !aCurrParams->IsCurved() ) if( !aCurrParams->IsCurved() )
{ {