CADSTAR PCB: Handle route offset

The CADSTAR post processor has a peculiar feature called "route offset"
which effectively shortens tracks when the pad, track or via that it
connects to has a smaller width. This operation is not saved in the
design itself, but applied as a post processing operation meaning that
the importer has to apply it when loading on the board.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/6648
This commit is contained in:
Roberto Fernandez Bautista 2021-03-25 11:28:22 +00:00
parent 1468764f83
commit 107a1990c9
2 changed files with 171 additions and 17 deletions

View File

@ -1938,21 +1938,18 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadNets()
NET_PCB net = netPair.second;
wxString netnameForErrorReporting = net.Name;
std::map<NETELEMENT_ID, long> netelementSizes;
if( netnameForErrorReporting.IsEmpty() )
netnameForErrorReporting = wxString::Format( "$%ld", net.SignalNum );
for( NET_PCB::CONNECTION_PCB connection : net.Connections )
{
if( !connection.Unrouted )
loadNetTracks( net.ID, connection.Route );
//TODO: all other elements
}
for( std::pair<NETELEMENT_ID, NET_PCB::VIA> viaPair : net.Vias )
{
NET_PCB::VIA via = viaPair.second;
loadNetVia( net.ID, via );
// viasize is used for calculating route offset (as done in CADSTAR post processor)
int viaSize = loadNetVia( net.ID, via );
netelementSizes.insert( { viaPair.first, viaSize } );
}
for( std::pair<NETELEMENT_ID, NET_PCB::PIN> pinPair : net.Pins )
@ -1979,9 +1976,68 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadNets()
{
// The below works because we have added the pads in the correct order to the
// footprint and the PAD_ID in Cadstar is a sequential, numerical ID
footprint->Pads().at( pin.PadID - (long) 1 )->SetNet( getKiCadNet( net.ID ) );
PAD* pad = footprint->Pads().at( pin.PadID - (long) 1 );
pad->SetNet( getKiCadNet( net.ID ) );
// padsize is used for calculating route offset (as done in CADSTAR post processor)
int padsize = std::min( pad->GetSizeX(), pad->GetSizeY() );
netelementSizes.insert( { pinPair.first, padsize } );
}
}
// For junction points we need to find out the biggest size of the other routes connecting
// at the junction in order to correctly apply the same "route offset" operation that the
// CADSTAR post processor applies when generating Manufacturing output
auto getJunctionSize =
[&]( NETELEMENT_ID aJptNetElemId, NET_PCB::CONNECTION_PCB aConnectionToIgnore ) -> int
{
int jptsize = 0;
for( NET_PCB::CONNECTION_PCB connection : net.Connections )
{
if( connection.Route.RouteVertices.size() == 0 )
continue;
if( connection.StartNode == aConnectionToIgnore.StartNode
&& connection.EndNode == aConnectionToIgnore.EndNode )
continue;
if( connection.StartNode == aJptNetElemId )
{
int s = getKiCadLength( connection.Route.RouteVertices.front().RouteWidth );
jptsize = std::max( jptsize, s );
}
else if( connection.EndNode == aJptNetElemId )
{
int s = getKiCadLength( connection.Route.RouteVertices.back().RouteWidth );
jptsize = std::max( jptsize, s );
}
}
return jptsize;
};
for( NET_PCB::CONNECTION_PCB connection : net.Connections )
{
int startSize = std::numeric_limits<int>::max();
int endSize = std::numeric_limits<int>::max();
if( netelementSizes.find( connection.StartNode ) != netelementSizes.end() )
startSize = netelementSizes.at( connection.StartNode );
else if( net.Junctions.find( connection.StartNode ) != net.Junctions.end() )
startSize = getJunctionSize( connection.StartNode, connection );
if( netelementSizes.find( connection.EndNode ) != netelementSizes.end() )
endSize = netelementSizes.at( connection.EndNode );
else if( net.Junctions.find( connection.EndNode ) != net.Junctions.end() )
endSize = getJunctionSize( connection.EndNode, connection );
startSize /= KiCadUnitMultiplier;
endSize /= KiCadUnitMultiplier;
if( !connection.Unrouted )
loadNetTracks( net.ID, connection.Route, startSize, endSize );
}
}
}
@ -2086,18 +2142,53 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadComponentAttributes( const COMPONENT& aComp
}
void CADSTAR_PCB_ARCHIVE_LOADER::loadNetTracks(
const NET_ID& aCadstarNetID, const NET_PCB::ROUTE& aCadstarRoute )
void CADSTAR_PCB_ARCHIVE_LOADER::loadNetTracks( const NET_ID& aCadstarNetID,
const NET_PCB::ROUTE& aCadstarRoute,
long aStartWidth, long aEndWidth )
{
std::vector<PCB_SHAPE*> shapes;
POINT prevEnd = aCadstarRoute.StartPoint;
std::vector<NET_PCB::ROUTE_VERTEX> offsetedVertices = aCadstarRoute.RouteVertices;
POINT newStartPoint = aCadstarRoute.StartPoint;
auto begin = offsetedVertices.begin();
for( const NET_PCB::ROUTE_VERTEX& v : aCadstarRoute.RouteVertices )
// First iterate through the points and apply route offset to start and end points only
// the rest of route offseting will happen in makeTracksFromDrawsegments
for( auto it = begin, end = offsetedVertices.end(); it != end; ++it )
{
auto next = std::next( it );
if( it == offsetedVertices.begin() )
{
// second point of the route (first point is given by aCadstarRoute.StartPoint)
int offsetAmount = ( it->RouteWidth / 2 ) - ( aStartWidth / 2 );
if( aStartWidth < it->RouteWidth )
applyRouteOffset( &newStartPoint, it->Vertex.End, offsetAmount );
}
if( next == end )
{
// last point of the route
int offsetAmount = ( it->RouteWidth / 2 ) - ( aEndWidth / 2 );
POINT referencePoint = newStartPoint;
if( it != begin )
referencePoint = std::prev( it )->Vertex.End;
if( aEndWidth < it->RouteWidth )
applyRouteOffset( &it->Vertex.End, referencePoint, offsetAmount );
}
}
POINT prevEnd = newStartPoint;
for( const NET_PCB::ROUTE_VERTEX& v : offsetedVertices )
{
PCB_SHAPE* shape = getDrawSegmentFromVertex( prevEnd, v.Vertex );
shape->SetLayer( getKiCadLayer( aCadstarRoute.LayerID ) );
shape->SetWidth( getKiCadLength( v.RouteWidth ) );
shape->SetLocked( v.Fixed );
shapes.push_back( shape );
prevEnd = v.Vertex.End;
}
@ -2112,7 +2203,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadNetTracks(
}
void CADSTAR_PCB_ARCHIVE_LOADER::loadNetVia(
int CADSTAR_PCB_ARCHIVE_LOADER::loadNetVia(
const NET_ID& aCadstarNetID, const NET_PCB::VIA& aCadstarVia )
{
VIA* via = new VIA( m_board );
@ -2159,6 +2250,8 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadNetVia(
getKiCadCopperLayerID( csLayerPair.PhysicalLayerEnd ) );
via->SetNet( getKiCadNet( aCadstarNetID ) );
///todo add netcode to the via
return via->GetWidth();
}
@ -2704,6 +2797,7 @@ std::vector<TRACK*> CADSTAR_PCB_ARCHIVE_LOADER::makeTracksFromDrawsegments(
int aWidthOverride )
{
std::vector<TRACK*> tracks;
TRACK* prevTrack = nullptr;
for( PCB_SHAPE* ds : aDrawsegments )
{
@ -2758,6 +2852,30 @@ std::vector<TRACK*> CADSTAR_PCB_ARCHIVE_LOADER::makeTracksFromDrawsegments(
if( aNet != nullptr )
track->SetNet( aNet );
track->SetLocked( ds->IsLocked() );
// Apply route offsetting, mimmicking the behaviour of the CADSTAR post processor
if( prevTrack != nullptr )
{
int offsetAmount = ( track->GetWidth() / 2 ) - ( prevTrack->GetWidth() / 2 );
if( offsetAmount > 0 )
{
// modify the start of the current track
wxPoint newStart = track->GetStart();
applyRouteOffset( &newStart, track->GetEnd(), offsetAmount );
track->SetStart( newStart );
}
else if( offsetAmount < 0 )
{
// ammend the end of the previous track
wxPoint newEnd = prevTrack->GetEnd();
applyRouteOffset( &newEnd, prevTrack->GetStart(), -offsetAmount );
prevTrack->SetEnd( newEnd );
} // don't do anything if offsetAmount == 0
}
prevTrack = track;
tracks.push_back( track );
aParentContainer->Add( track, ADD_MODE::APPEND );
}
@ -2902,6 +3020,27 @@ void CADSTAR_PCB_ARCHIVE_LOADER::addAttribute( const ATTRIBUTE_LOCATION& aCadsta
}
void CADSTAR_PCB_ARCHIVE_LOADER::applyRouteOffset( wxPoint* aPointToOffset,
const wxPoint& aRefPoint,
const long& aOffsetAmount )
{
VECTOR2I v( *aPointToOffset - aRefPoint );
int newLength = v.EuclideanNorm() - aOffsetAmount;
if( newLength > 0 )
{
VECTOR2I offsetted = v.Resize( newLength ) + VECTOR2I( aRefPoint );
aPointToOffset->x = offsetted.x;
aPointToOffset->y = offsetted.y;
}
else
{
*aPointToOffset = aRefPoint; // zero length track. Needs to be removed to mimmick
// cadstar behaviour
}
}
int CADSTAR_PCB_ARCHIVE_LOADER::getLineThickness( const LINECODE_ID& aCadstarLineCodeID )
{
wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )

View File

@ -148,8 +148,12 @@ private:
void loadLibraryAreas( const SYMDEF_PCB& aComponent, FOOTPRINT* aFootprint );
void loadLibraryPads( const SYMDEF_PCB& aComponent, FOOTPRINT* aFootprint );
void loadComponentAttributes( const COMPONENT& aComponent, FOOTPRINT* aFootprint );
void loadNetTracks( const NET_ID& aCadstarNetID, const NET_PCB::ROUTE& aCadstarRoute );
void loadNetVia( const NET_ID& aCadstarNetID, const NET_PCB::VIA& aCadstarVia );
void loadNetTracks( const NET_ID& aCadstarNetID, const NET_PCB::ROUTE& aCadstarRoute,
long aStartWidth = std::numeric_limits<long>::max(),
long aEndWidth = std::numeric_limits<long>::max() );
/// Load via and return via size
int loadNetVia( const NET_ID& aCadstarNetID, const NET_PCB::VIA& aCadstarVia );
void checkAndLogHatchCode( const HATCHCODE_ID& aCadstarHatchcodeID );
void applyDimensionSettings( const DIMENSION& aCadstarDim, DIMENSION_BASE* aKiCadDim );
@ -362,6 +366,17 @@ private:
const ATTRIBUTE_ID& aCadstarAttributeID, FOOTPRINT* aFootprint,
const wxString& aAttributeValue );
/**
* @brief CADSTAR's Post Processor does an action called "Route Offset" which
* is applied when a route is wider than the pad on which it is terminating or
* when there are different widths of route, in order to reduce overlap.
* @param aPointToOffset Point that we want to offset by aOffsetAmount
* @param aRefPoint Reference point to use for determine the angle of the offset
* @param aOffsetAmount
*/
void applyRouteOffset( wxPoint* aPointToOffset, const wxPoint& aRefPoint,
const long& aOffsetAmount );
//Helper Functions for obtaining CADSTAR elements in the parsed structures
int getLineThickness( const LINECODE_ID& aCadstarLineCodeID );
COPPERCODE getCopperCode( const COPPERCODE_ID& aCadstaCopperCodeID );