Move 3D polygon approximation to absolute-error algorithm.

Also inflates via and pad hole polygons to bisect their circles.

Fixes: lp:1758137
* https://bugs.launchpad.net/kicad/+bug/1758137
This commit is contained in:
Jeff Young 2018-03-22 19:15:34 +00:00
parent fbf10e941b
commit cd0cd242d1
3 changed files with 24 additions and 43 deletions

View File

@ -33,6 +33,7 @@
#include <class_board.h>
#include <3d_math.h>
#include "3d_fastmath.h"
#include <geometry/geometry_utils.h>
/**
* Trace mask used to enable or disable the trace output of this class.
@ -243,37 +244,19 @@ int CINFO3D_VISU::GetCopperThicknessBIU() const
return COPPER_THICKNESS;
}
// Constant factors used for number of segments approximation calcs
#define MIN_SEG_PER_CIRCLE 12
#define MAX_SEG_PER_CIRCLE 48
#define SEG_MIN_FACTOR_BIU ( 0.10f * IU_PER_MM )
#define SEG_MAX_FACTOR_BIU ( 6.00f * IU_PER_MM )
unsigned int CINFO3D_VISU::GetNrSegmentsCircle( float aDiameter3DU ) const
{
wxASSERT( aDiameter3DU > 0.0f );
unsigned int result = mapf( aDiameter3DU,
m_calc_seg_min_factor3DU, m_calc_seg_max_factor3DU,
(float)MIN_SEG_PER_CIRCLE, (float)MAX_SEG_PER_CIRCLE );
wxASSERT( result > 1 );
return result;
return GetNrSegmentsCircle( (int)( aDiameter3DU / m_biuTo3Dunits ) );
}
unsigned int CINFO3D_VISU::GetNrSegmentsCircle( int aDiameterBUI ) const
unsigned int CINFO3D_VISU::GetNrSegmentsCircle( int aDiameterBIU ) const
{
wxASSERT( aDiameterBUI > 0 );
wxASSERT( aDiameterBIU > 0 );
unsigned int result = mapf( (float)aDiameterBUI,
(float)SEG_MIN_FACTOR_BIU, (float)SEG_MAX_FACTOR_BIU,
(float)MIN_SEG_PER_CIRCLE, (float)MAX_SEG_PER_CIRCLE );
wxASSERT( result > 1 );
return result;
return GetArcToSegmentCount( aDiameterBIU / 2, ARC_HIGH_DEF, 360.0 );
}
@ -281,7 +264,7 @@ double CINFO3D_VISU::GetCircleCorrectionFactor( int aNrSides ) const
{
wxASSERT( aNrSides >= 3 );
return 1.0 / cos( M_PI / ( (double)aNrSides * 2.0 ) );
return GetCircletoPolyCorrectionFactor( aNrSides );
}
@ -318,10 +301,6 @@ void CINFO3D_VISU::InitSettings( REPORTER *aStatusTextReporter )
// Calculate the convertion to apply to all positions.
m_biuTo3Dunits = RANGE_SCALE_3D / std::max( m_boardSize.x, m_boardSize.y );
// Calculate factors for cicle segment approximation
m_calc_seg_min_factor3DU = (float)( SEG_MIN_FACTOR_BIU * m_biuTo3Dunits );
m_calc_seg_max_factor3DU = (float)( SEG_MAX_FACTOR_BIU * m_biuTo3Dunits );
m_epoxyThickness3DU = m_board->GetDesignSettings().GetBoardThickness() *
m_biuTo3Dunits;

View File

@ -394,10 +394,10 @@ class CINFO3D_VISU
/**
* @brief GetNrSegmentsCircle
* @param aDiameterBUI: diameter in board unities
* @param aDiameterBIU: diameter in board internal units
* @return number of sides that should be used in that circle
*/
unsigned int GetNrSegmentsCircle( int aDiameterBUI ) const;
unsigned int GetNrSegmentsCircle( int aDiameterBIU ) const;
/**
* @brief GetCircleCorrectionFactor - computes a angle correction

View File

@ -768,9 +768,11 @@ void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads()
{
const VIA *via = static_cast<const VIA*>(track);
const float holediameter = via->GetDrillValue() * m_settings.BiuTo3Dunits();
const float thickness = m_settings.GetCopperThickness3DU();
const float hole_inner_radius = ( holediameter / 2.0f );
const float holediameter = via->GetDrillValue() * m_settings.BiuTo3Dunits();
const float thickness = m_settings.GetCopperThickness3DU();
const int nrSegments = m_settings.GetNrSegmentsCircle( via->GetDrillValue() );
const double correctionFactor = m_settings.GetCircleCorrectionFactor( nrSegments );
const float hole_inner_radius = ( holediameter / 2.0f ) * correctionFactor;
const SFVEC2F via_center( via->GetStart().x * m_settings.BiuTo3Dunits(),
-via->GetStart().y * m_settings.BiuTo3Dunits() );
@ -790,7 +792,7 @@ void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads()
hole_inner_radius + thickness,
ztop,
zbot,
m_settings.GetNrSegmentsCircle( via->GetDrillValue() ),
nrSegments,
layerTriangleVIA );
}
}
@ -829,20 +831,20 @@ void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads()
// we use the hole diameter to calculate the seg count.
// for round holes, drillsize.x == drillsize.y
// for oblong holes, the diameter is the smaller of
// (drillsize.x, drillsize.y)
const int diam = std::min( drillsize.x, drillsize.y ) +
m_settings.GetCopperThicknessBIU() * 2;
const int segmentsPerCircle = m_settings.GetNrSegmentsCircle( diam );
// for slots, the diameter is the smaller of (drillsize.x, drillsize.y)
int copperThickness = m_settings.GetCopperThicknessBIU();
int radius = std::min( drillsize.x, drillsize.y ) / 2 + copperThickness;
int nrSegments = m_settings.GetNrSegmentsCircle( radius * 2 );
double correctionFactor = m_settings.GetCircleCorrectionFactor( nrSegments );
int correction = radius * ( correctionFactor - 1 );
pad->BuildPadDrillShapePolygon( tht_outer_holes_poly,
m_settings.GetCopperThicknessBIU(),
segmentsPerCircle );
copperThickness + correction,
nrSegments );
pad->BuildPadDrillShapePolygon( tht_inner_holes_poly,
0,
segmentsPerCircle );
correction,
nrSegments );
}
}
}