Guard 3D viewer against degenerate shapes.

Fixes https://gitlab.com/kicad/code/kicad/issues/13693
This commit is contained in:
Jeff Young 2023-01-29 22:39:29 +00:00
parent 1ee9d538da
commit 203f0f66fb
2 changed files with 96 additions and 27 deletions

View File

@ -112,8 +112,13 @@ void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContaine
const SFVEC2F pt1_3DU = TO_SFVEC2F( aPt1 ); const SFVEC2F pt1_3DU = TO_SFVEC2F( aPt1 );
const SFVEC2F pt2_3DU = TO_SFVEC2F( aPt2 ); const SFVEC2F pt2_3DU = TO_SFVEC2F( aPt2 );
if( Is_segment_a_circle( pt1_3DU, pt2_3DU ) ) if( penWidth_3DU == 0.0 )
{ {
// Don't attempt to render degenerate shapes
}
else if( Is_segment_a_circle( pt1_3DU, pt2_3DU ) )
{
// Cannot add segments that have the same start and end point
aContainer->Add( new FILLED_CIRCLE_2D( pt1_3DU, penWidth_3DU / 2, aContainer->Add( new FILLED_CIRCLE_2D( pt1_3DU, penWidth_3DU / 2,
*aOwner ) ); *aOwner ) );
} }
@ -253,7 +258,10 @@ void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDs
case PCB_VIA_T: case PCB_VIA_T:
{ {
const float radius3DU = TO_3DU( aTrack->GetWidth() / 2 ); const float radius3DU = TO_3DU( aTrack->GetWidth() / 2 );
aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius3DU, *aTrack ) );
if( radius3DU > 0.0 )
aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius3DU, *aTrack ) );
break; break;
} }
@ -286,9 +294,13 @@ void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDs
case PCB_TRACE_T: // Track is a usual straight segment case PCB_TRACE_T: // Track is a usual straight segment
{ {
// Cannot add segments that have the same start and end point if( aTrack->GetWidth() == 0 )
if( Is_segment_a_circle( start3DU, end3DU ) )
{ {
// Don't attempt to render degenerate shapes
}
else if( Is_segment_a_circle( start3DU, end3DU ) )
{
// Cannot add segments that have the same start and end point
aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aTrack->GetWidth() / 2 ), aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aTrack->GetWidth() / 2 ),
*aTrack ) ); *aTrack ) );
} }
@ -350,13 +362,22 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aCo
const SFVEC2F b3DU = TO_SFVEC2F( seg->GetSeg().B ); const SFVEC2F b3DU = TO_SFVEC2F( seg->GetSeg().B );
const double width3DU = TO_3DU( seg->GetWidth() + clearance.x * 2 ); const double width3DU = TO_3DU( seg->GetWidth() + clearance.x * 2 );
// Cannot add segments that have the same start and end point if( width3DU == 0.0 )
if( Is_segment_a_circle( a3DU, b3DU ) ) {
// Don't attempt to render degenerate shapes
}
else if( Is_segment_a_circle( a3DU, b3DU ) )
{
// Cannot add segments that have the same start and end point
aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) ); aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) );
}
else else
{
aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) ); aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) );
} }
break; break;
}
case SH_CIRCLE: case SH_CIRCLE:
{ {
@ -366,10 +387,11 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aCo
const SFVEC2F center3DU = TO_SFVEC2F( circle->GetCenter() ); const SFVEC2F center3DU = TO_SFVEC2F( circle->GetCenter() );
// Don't render zero radius circles // Don't render zero radius circles
if( radius3DU != 0.0 ) if( radius3DU > 0.0 )
aContainer->Add( new FILLED_CIRCLE_2D( center3DU, radius3DU, *aPad ) ); aContainer->Add( new FILLED_CIRCLE_2D( center3DU, radius3DU, *aPad ) );
}
break; break;
}
case SH_RECT: case SH_RECT:
{ {
@ -380,8 +402,8 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aCo
poly.Append( rect->GetPosition().x + rect->GetSize().x, rect->GetPosition().y ); poly.Append( rect->GetPosition().x + rect->GetSize().x, rect->GetPosition().y );
poly.Append( rect->GetPosition() + rect->GetSize() ); poly.Append( rect->GetPosition() + rect->GetSize() );
poly.Append( rect->GetPosition().x, rect->GetPosition().y + rect->GetSize().y ); poly.Append( rect->GetPosition().x, rect->GetPosition().y + rect->GetSize().y );
}
break; break;
}
case SH_SIMPLE: case SH_SIMPLE:
poly.AddOutline( static_cast<const SHAPE_SIMPLE*>( shape )->Vertices() ); poly.AddOutline( static_cast<const SHAPE_SIMPLE*>( shape )->Vertices() );
@ -403,14 +425,23 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aCo
const SFVEC2F b3DU = TO_SFVEC2F( seg.GetSeg().B ); const SFVEC2F b3DU = TO_SFVEC2F( seg.GetSeg().B );
const double width3DU = TO_3DU( arc->GetWidth() + clearance.x * 2 ); const double width3DU = TO_3DU( arc->GetWidth() + clearance.x * 2 );
// Cannot add segments that have the same start and end point if( width3DU == 0.0 )
if( Is_segment_a_circle( a3DU, b3DU ) ) {
// Don't attempt to render degenerate shapes
}
else if( Is_segment_a_circle( a3DU, b3DU ) )
{
// Cannot add segments that have the same start and end point
aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) ); aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) );
}
else else
{
aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) ); aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) );
}
} }
}
break; break;
}
default: default:
UNIMPLEMENTED_FOR( SHAPE_TYPE_asString( shape->Type() ) ); UNIMPLEMENTED_FOR( SHAPE_TYPE_asString( shape->Type() ) );
@ -543,6 +574,10 @@ void BOARD_ADAPTER::transformArcToSegments( const VECTOR2I& aCentre, const VECTO
int aWidth, CONTAINER_2D_BASE* aContainer, int aWidth, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM& aOwner ) const BOARD_ITEM& aOwner )
{ {
// Don't attempt to render degenerate shapes
if( aWidth == 0 )
return;
VECTOR2I arc_start, arc_end; VECTOR2I arc_start, arc_end;
EDA_ANGLE arcAngle( aArcAngle ); EDA_ANGLE arcAngle( aArcAngle );
EDA_ANGLE delta = ANGLE_360 / aCircleToSegmentsCount; // rotate angle EDA_ANGLE delta = ANGLE_360 / aCircleToSegmentsCount; // rotate angle
@ -610,12 +645,22 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
float outer_radius3DU = TO_3DU( aShape->GetRadius() + linewidth / 2 ); float outer_radius3DU = TO_3DU( aShape->GetRadius() + linewidth / 2 );
if( inner_radius3DU < 0 ) if( inner_radius3DU < 0 )
inner_radius3DU = 0; inner_radius3DU = 0.0;
if( aShape->IsFilled() ) if( outer_radius3DU == 0.0 )
aContainer->Add( new FILLED_CIRCLE_2D( center3DU, outer_radius3DU, *aOwner ) ); {
// Don't attempt to render degenerate shapes
}
else if( aShape->IsFilled() )
{
aContainer->Add( new FILLED_CIRCLE_2D( center3DU, outer_radius3DU,
*aOwner ) );
}
else else
aContainer->Add( new RING_2D( center3DU, inner_radius3DU, outer_radius3DU, *aOwner ) ); {
aContainer->Add( new RING_2D( center3DU, inner_radius3DU, outer_radius3DU,
*aOwner ) );
}
break; break;
} }
@ -653,8 +698,8 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
transformArcToSegments( aShape->GetCenter(), aShape->GetStart(), aShape->GetArcAngle(), transformArcToSegments( aShape->GetCenter(), aShape->GetStart(), aShape->GetArcAngle(),
segCount, linewidth, aContainer, *aOwner ); segCount, linewidth, aContainer, *aOwner );
break;
} }
break;
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
{ {
@ -662,12 +707,22 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
const SFVEC2F end3DU = TO_SFVEC2F( aShape->GetEnd() ); const SFVEC2F end3DU = TO_SFVEC2F( aShape->GetEnd() );
const double linewidth3DU = TO_3DU( linewidth ); const double linewidth3DU = TO_3DU( linewidth );
if( Is_segment_a_circle( start3DU, end3DU ) ) if( linewidth3DU == 0.0 )
{
// Don't attempt to render degenerate shapes
}
else if( Is_segment_a_circle( start3DU, end3DU ) )
{
// Cannot add segments that have the same start and end point
aContainer->Add( new FILLED_CIRCLE_2D( start3DU, linewidth3DU / 2, *aOwner ) ); aContainer->Add( new FILLED_CIRCLE_2D( start3DU, linewidth3DU / 2, *aOwner ) );
}
else else
{
aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, linewidth3DU, *aOwner ) ); aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, linewidth3DU, *aOwner ) );
}
break;
} }
break;
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
case SHAPE_T::POLY: case SHAPE_T::POLY:
@ -681,8 +736,8 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
break; break;
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner ); ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
break;
} }
break;
default: default:
wxFAIL_MSG( wxT( "BOARD_ADAPTER::addShape no implementation for " ) wxFAIL_MSG( wxT( "BOARD_ADAPTER::addShape no implementation for " )
@ -690,7 +745,7 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
break; break;
} }
} }
else else if( linewidth > 0 )
{ {
std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true ); std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
SFVEC2F a3DU; SFVEC2F a3DU;
@ -757,9 +812,18 @@ void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BAS
SFVEC2F start3DU = TO_SFVEC2F( path.CPoint( j ) ); SFVEC2F start3DU = TO_SFVEC2F( path.CPoint( j ) );
SFVEC2F end3DU = TO_SFVEC2F( path.CPoint( j + 1 ) ); SFVEC2F end3DU = TO_SFVEC2F( path.CPoint( j + 1 ) );
if( Is_segment_a_circle( start3DU, end3DU ) ) if( aWidth == 0 )
{
// Don't attempt to render degenerate shapes
}
else if( Is_segment_a_circle( start3DU, end3DU ) )
{
// Cannot add segments that have the same start and end point
aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), *aPad ) ); aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), *aPad ) );
}
else else
{
aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), *aPad ) ); aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), *aPad ) );
}
} }
} }

View File

@ -279,7 +279,6 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
if( viatype != VIATYPE::THROUGH ) if( viatype != VIATYPE::THROUGH )
{ {
// Add hole objects // Add hole objects
BVH_CONTAINER_2D *layerHoleContainer = nullptr; BVH_CONTAINER_2D *layerHoleContainer = nullptr;
@ -311,15 +310,21 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
hole_inner_radius + thickness, hole_inner_radius + thickness,
*track ) ); *track ) );
if( m_Cfg->m_Render.clip_silk_on_via_annulus && m_Cfg->m_Render.realistic ) if( m_Cfg->m_Render.clip_silk_on_via_annulus
&& m_Cfg->m_Render.realistic
&& ring_radius > 0.0 )
{ {
m_throughHoleAnnularRings.Add( new FILLED_CIRCLE_2D( via_center, m_throughHoleAnnularRings.Add( new FILLED_CIRCLE_2D( via_center,
ring_radius, ring_radius,
*track ) ); *track ) );
} }
m_throughHoleIds.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius, if( hole_inner_radius > 0.0 )
*track ) ); {
m_throughHoleIds.Add( new FILLED_CIRCLE_2D( via_center,
hole_inner_radius,
*track ) );
}
} }
} }
} }