Clean up arc/circle polygonization.
1) For a while now we've been using a calculated seg count from a given maxError, and a correction factor to push the radius out so that all the error is outside the arc/circle. However, the second calculation (which pre-dates the first) is pretty much just the inverse of the first (and yields nothing more than maxError back). This is particularly sub-optimal given the cost of trig functions. 2) There are a lot of old optimizations to reduce segcounts in certain situations, someting that our error-based calculation compensates for anyway. (Smaller radii need fewer segments to meet the maxError condition.) But perhaps more importantly we now surface maxError in the UI and we don't really want to call it "Max deviation except when it's not". 3) We were also clamping the segCount twice: once in the calculation routine and once in most of it's callers. Furthermore, the caller clamping was inconsistent (both in being done and in the clamping value). We now clamp only in the calculation routine. 4) There's no reason to use the correction factors in the 3Dviewer; it's just a visualization and whether the polygonization error is inside or outside the shape isn't really material. 5) The arc-correction-disabling stuff (used for solder mask layer) was somewhat fragile in that it depended on the caller to turn it back on afterwards. It's now only exposed as a RAII object which automatically cleans up when it goes out of scope. 6) There were also bugs in a couple of the polygonization routines where we'd accumulate round-off error in adding up the segments and end up with an overly long last segment (which of course would voilate the error max). This was the cause of the linked bug and also some issues with vias that we had fudged in the past with extra clearance. Fixes https://gitlab.com/kicad/code/kicad/issues/5567
This commit is contained in:
parent
f493e270ea
commit
e2bc7557cc
|
@ -256,16 +256,7 @@ unsigned int BOARD_ADAPTER::GetNrSegmentsCircle( int aDiameterBIU ) const
|
||||||
{
|
{
|
||||||
wxASSERT( aDiameterBIU > 0 );
|
wxASSERT( aDiameterBIU > 0 );
|
||||||
|
|
||||||
// Require at least 3 segments for a circle
|
return GetArcToSegmentCount( aDiameterBIU / 2, ARC_HIGH_DEF, 360.0 );
|
||||||
return std::max( GetArcToSegmentCount( aDiameterBIU / 2, ARC_HIGH_DEF, 360.0 ), 3 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
double BOARD_ADAPTER::GetCircleCorrectionFactor( int aNrSides ) const
|
|
||||||
{
|
|
||||||
wxASSERT( aNrSides >= 3 );
|
|
||||||
|
|
||||||
return GetCircletoPolyCorrectionFactor( aNrSides );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -529,14 +529,6 @@ class BOARD_ADAPTER
|
||||||
*/
|
*/
|
||||||
unsigned int GetNrSegmentsCircle( int aDiameterBIU ) const;
|
unsigned int GetNrSegmentsCircle( int aDiameterBIU ) const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief GetCircleCorrectionFactor - computes a angle correction
|
|
||||||
* factor used when creating circles
|
|
||||||
* @param aNrSides: the number of segments sides of the circle
|
|
||||||
* @return a factor to apply to contour creation
|
|
||||||
*/
|
|
||||||
double GetCircleCorrectionFactor( int aNrSides ) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief GetPolyMap - Get maps of polygons's layers
|
* @brief GetPolyMap - Get maps of polygons's layers
|
||||||
* @return the map with polygons's layers
|
* @return the map with polygons's layers
|
||||||
|
|
|
@ -54,8 +54,7 @@ void BOARD_ADAPTER::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
||||||
const VECTOR2I& a = path.CPoint( ii );
|
const VECTOR2I& a = path.CPoint( ii );
|
||||||
const VECTOR2I& b = path.CPoint( ii + 1 );
|
const VECTOR2I& b = path.CPoint( ii + 1 );
|
||||||
|
|
||||||
TransformSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ), wxPoint( b.x, b.y ),
|
TransformOvalToPolygon( aCornerBuffer, (wxPoint) a, (wxPoint) b, aWidth, ARC_HIGH_DEF );
|
||||||
ARC_HIGH_DEF, aWidth );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -744,8 +744,7 @@ void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads()
|
||||||
const float holediameter = via->GetDrillValue() * m_boardAdapter.BiuTo3Dunits();
|
const float holediameter = via->GetDrillValue() * m_boardAdapter.BiuTo3Dunits();
|
||||||
const float thickness = m_boardAdapter.GetCopperThickness3DU();
|
const float thickness = m_boardAdapter.GetCopperThickness3DU();
|
||||||
const int nrSegments = m_boardAdapter.GetNrSegmentsCircle( via->GetDrillValue() );
|
const int nrSegments = m_boardAdapter.GetNrSegmentsCircle( via->GetDrillValue() );
|
||||||
const double correctionFactor = m_boardAdapter.GetCircleCorrectionFactor( nrSegments );
|
const float hole_inner_radius = holediameter / 2.0f;
|
||||||
const float hole_inner_radius = ( holediameter / 2.0f ) * correctionFactor;
|
|
||||||
|
|
||||||
const SFVEC2F via_center( via->GetStart().x * m_boardAdapter.BiuTo3Dunits(),
|
const SFVEC2F via_center( via->GetStart().x * m_boardAdapter.BiuTo3Dunits(),
|
||||||
-via->GetStart().y * m_boardAdapter.BiuTo3Dunits() );
|
-via->GetStart().y * m_boardAdapter.BiuTo3Dunits() );
|
||||||
|
@ -805,14 +804,11 @@ void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads()
|
||||||
// for slots, the diameter is the smaller of (drillsize.x, drillsize.y)
|
// for slots, the diameter is the smaller of (drillsize.x, drillsize.y)
|
||||||
int copperThickness = m_boardAdapter.GetCopperThicknessBIU();
|
int copperThickness = m_boardAdapter.GetCopperThicknessBIU();
|
||||||
int radius = std::min( drillsize.x, drillsize.y ) / 2 + copperThickness;
|
int radius = std::min( drillsize.x, drillsize.y ) / 2 + copperThickness;
|
||||||
int nrSegments = m_boardAdapter.GetNrSegmentsCircle( radius * 2 );
|
|
||||||
double correctionFactor = m_boardAdapter.GetCircleCorrectionFactor( nrSegments );
|
|
||||||
int correction = radius * ( correctionFactor - 1 );
|
|
||||||
|
|
||||||
pad->TransformHoleWithClearanceToPolygon( tht_outer_holes_poly,
|
pad->TransformHoleWithClearanceToPolygon( tht_outer_holes_poly,
|
||||||
copperThickness + correction );
|
copperThickness + radius );
|
||||||
|
|
||||||
pad->TransformHoleWithClearanceToPolygon( tht_inner_holes_poly, correction );
|
pad->TransformHoleWithClearanceToPolygon( tht_inner_holes_poly, radius );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -533,8 +533,8 @@ void DXF_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
|
||||||
// enter outline as polygon:
|
// enter outline as polygon:
|
||||||
for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
|
for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
|
||||||
{
|
{
|
||||||
TransformSegmentToPolygon( bufferOutline,
|
TransformOvalToPolygon( bufferOutline, aCornerList[ ii - 1 ], aCornerList[ ii ],
|
||||||
aCornerList[ ii - 1 ], aCornerList[ ii ], GetPlotterArcHighDef(), aWidth );
|
aWidth, GetPlotterArcHighDef() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// enter the initial polygon:
|
// enter the initial polygon:
|
||||||
|
|
|
@ -121,22 +121,6 @@ void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
double aRotation, int aCornerRadius,
|
double aRotation, int aCornerRadius,
|
||||||
double aChamferRatio, int aChamferCorners, int aError );
|
double aChamferRatio, int aChamferCorners, int aError );
|
||||||
|
|
||||||
/**
|
|
||||||
* Function TransformRoundedEndsSegmentToPolygon
|
|
||||||
* convert a segment with rounded ends to a polygon
|
|
||||||
* Convert arcs to multiple straight lines
|
|
||||||
* @param aCornerBuffer = a buffer to store the polygon
|
|
||||||
* @param aStart = the segment start point coordinate
|
|
||||||
* @param aEnd = the segment end point coordinate
|
|
||||||
* @param aError = the IU allowed for error in approximation
|
|
||||||
* @param aWidth = the segment width
|
|
||||||
* Note: the polygon is inside the arc ends, so if you want to have the polygon
|
|
||||||
* outside the circle, you should give aStart and aEnd calculated with a correction factor
|
|
||||||
*/
|
|
||||||
void TransformSegmentToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoint aEnd,
|
|
||||||
int aError, int aWidth );
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function TransformArcToPolygon
|
* Function TransformArcToPolygon
|
||||||
* Creates a polygon from an Arc
|
* Creates a polygon from an Arc
|
||||||
|
|
|
@ -47,36 +47,33 @@ class EDA_RECT;
|
||||||
*/
|
*/
|
||||||
int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree );
|
int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree );
|
||||||
|
|
||||||
/** When creating polygons to create a clearance polygonal area, the polygon must
|
/**
|
||||||
|
* When creating polygons to create a clearance polygonal area, the polygon must
|
||||||
* be same or bigger than the original shape.
|
* be same or bigger than the original shape.
|
||||||
* Polygons are bigger if the original shape has arcs (round rectangles, ovals, circles...)
|
* Polygons are bigger if the original shape has arcs (round rectangles, ovals,
|
||||||
* In some cases (in fact only one: when building layer solder mask) modifying
|
* circles...). However, when building the solder mask layer modifying the shapes
|
||||||
* shapes when converting them to polygons is not acceptable (the modification
|
* when converting them to polygons is not acceptable (the modification can break
|
||||||
* can break calculations)
|
* calculations).
|
||||||
* so one can disable the shape expansion by calling DisableArcRadiusCorrection( true )
|
* So one can disable the shape expansion within a particular scope by allocating
|
||||||
* Important: calling DisableArcRadiusCorrection( false ) after calculations is
|
* a DISABLE_ARC_CORRECTION.
|
||||||
* mandatory to break oher calculations
|
|
||||||
* @param aDisable = false to create polygons same or outside the original shape
|
|
||||||
* = true to create polygons same or inside the original shape and minimize
|
|
||||||
* shape geometric changes
|
|
||||||
*/
|
*/
|
||||||
void DisableArcRadiusCorrection( bool aDisable );
|
class DISABLE_ARC_RADIUS_CORRECTION
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DISABLE_ARC_RADIUS_CORRECTION();
|
||||||
|
~DISABLE_ARC_RADIUS_CORRECTION();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the correction factor to approximate a circle by segments or 1.0
|
* @return the radius correction to approximate a circle.
|
||||||
* depending on the last call to DisableArcRadiusCorrection()
|
* @param aMaxError is the same error value used to calculate the number of segments.
|
||||||
* @param aSegCountforCircle is the number of segments to approximate the circle
|
|
||||||
*
|
*
|
||||||
* When creating a polygon from a circle, the polygon is inside the circle.
|
* When creating a polygon from a circle, the polygon is inside the circle.
|
||||||
* Only corners are on the circle.
|
* Only corners are on the circle.
|
||||||
* This is incorrect when building clearance areas of circles, that need to build
|
* This is incorrect when building clearance areas of circles, that need to build
|
||||||
* the equivalent polygon outside the circle
|
* the equivalent polygon outside the circle.
|
||||||
* The correction factor is a scaling factor to apply to the radius to build a
|
|
||||||
* polygon outside the circle (only the middle of each segment is on the circle
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
double GetCircletoPolyCorrectionFactor( int aSegCountforCircle );
|
int GetCircleToPolyCorrection( int aMaxError );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Snap a vector onto the nearest 0, 45 or 90 degree line.
|
* Snap a vector onto the nearest 0, 45 or 90 degree line.
|
||||||
|
|
|
@ -42,17 +42,16 @@ void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aCornerBuffer, wxPoint aCenter,
|
||||||
int aError )
|
int aError )
|
||||||
{
|
{
|
||||||
wxPoint corner_position;
|
wxPoint corner_position;
|
||||||
int numSegs = std::max( GetArcToSegmentCount( aRadius, aError, 360.0 ), 6 );
|
int numSegs = GetArcToSegmentCount( aRadius, aError, 360.0 );
|
||||||
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
|
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
|
||||||
double correction = GetCircletoPolyCorrectionFactor( numSegs );
|
int correction = GetCircleToPolyCorrection( aError );
|
||||||
int radius = aRadius * correction; // make segments outside the circles
|
int radius = aRadius + correction; // make segments outside the circles
|
||||||
double halfstep = delta/2.0; // the starting value for rot angles
|
double halfstep = delta / 2.0; // the starting value for rot angles
|
||||||
|
|
||||||
for( int ii = 0; ii < numSegs; ii++ )
|
for( int angle = 0; angle < 3600; angle += delta )
|
||||||
{
|
{
|
||||||
corner_position.x = radius;
|
corner_position.x = radius;
|
||||||
corner_position.y = 0;
|
corner_position.y = 0;
|
||||||
double angle = (ii * delta) + halfstep;
|
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += aCenter;
|
corner_position += aCenter;
|
||||||
aCornerBuffer.Append( corner_position.x, corner_position.y );
|
aCornerBuffer.Append( corner_position.x, corner_position.y );
|
||||||
|
@ -66,23 +65,27 @@ void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCenter, i
|
||||||
int aError )
|
int aError )
|
||||||
{
|
{
|
||||||
wxPoint corner_position;
|
wxPoint corner_position;
|
||||||
int numSegs = std::max( GetArcToSegmentCount( aRadius, aError, 360.0 ), 6 );
|
int numSegs = GetArcToSegmentCount( aRadius, aError, 360.0 );
|
||||||
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
|
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
|
||||||
double correction = GetCircletoPolyCorrectionFactor( numSegs );
|
int correction = GetCircleToPolyCorrection( aError );
|
||||||
int radius = aRadius * correction; // make segments outside the circles
|
int radius = aRadius + correction; // make segments outside the circles
|
||||||
double halfstep = delta/2.0; // the starting value for rot angles
|
|
||||||
|
|
||||||
aCornerBuffer.NewOutline();
|
aCornerBuffer.NewOutline();
|
||||||
|
|
||||||
for( int ii = 0; ii < numSegs; ii++ )
|
for( int angle = 0; angle < 3600; angle += delta )
|
||||||
{
|
{
|
||||||
corner_position.x = radius;
|
corner_position.x = radius;
|
||||||
corner_position.y = 0;
|
corner_position.y = 0;
|
||||||
double angle = (ii * delta) + halfstep;
|
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += aCenter;
|
corner_position += aCenter;
|
||||||
aCornerBuffer.Append( corner_position.x, corner_position.y );
|
aCornerBuffer.Append( corner_position.x, corner_position.y );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finish circle
|
||||||
|
corner_position.x = radius;
|
||||||
|
corner_position.y = 0;
|
||||||
|
corner_position += aCenter;
|
||||||
|
aCornerBuffer.Append( corner_position.x, corner_position.y );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,17 +98,11 @@ void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPo
|
||||||
// so, later, we will clamp the polygonal shape with the bounding box
|
// so, later, we will clamp the polygonal shape with the bounding box
|
||||||
// of the segment.
|
// of the segment.
|
||||||
int radius = aWidth / 2;
|
int radius = aWidth / 2;
|
||||||
int numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ), 6 );
|
int numSegs = GetArcToSegmentCount( radius, aError, 360.0 );
|
||||||
|
|
||||||
// Because we want to create 2 arcs (one at each segment end) numSegs must be
|
|
||||||
// a even value (we will used numSegs/2 later)
|
|
||||||
if( numSegs % 2 != 0 )
|
|
||||||
numSegs++;
|
|
||||||
|
|
||||||
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
|
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
|
||||||
double correction = GetCircletoPolyCorrectionFactor( numSegs );
|
int correction = GetCircleToPolyCorrection( aError );
|
||||||
|
|
||||||
radius = radius * correction; // make segments outside the circles
|
radius += correction; // make segments outside the circles
|
||||||
|
|
||||||
// end point is the coordinate relative to aStart
|
// end point is the coordinate relative to aStart
|
||||||
wxPoint endp = aEnd - aStart;
|
wxPoint endp = aEnd - aStart;
|
||||||
|
@ -130,13 +127,14 @@ void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPo
|
||||||
|
|
||||||
// Compute the outlines of the segment, and creates a polygon
|
// Compute the outlines of the segment, and creates a polygon
|
||||||
// Note: the polygonal shape is built from the equivalent horizontal
|
// Note: the polygonal shape is built from the equivalent horizontal
|
||||||
// segment starting ar 0,0, and ending at seg_len,0
|
// segment starting at {0,0}, and ending at {seg_len,0}
|
||||||
|
|
||||||
// add right rounded end:
|
// add right rounded end:
|
||||||
for( int ii = 0; ii < numSegs / 2; ii++ )
|
|
||||||
|
for( int angle = 0; angle < 1800; angle += delta )
|
||||||
{
|
{
|
||||||
corner = wxPoint( 0, radius );
|
corner = wxPoint( 0, radius );
|
||||||
RotatePoint( &corner, delta * ii );
|
RotatePoint( &corner, angle );
|
||||||
corner.x += seg_len;
|
corner.x += seg_len;
|
||||||
polyshape.Append( corner.x, corner.y );
|
polyshape.Append( corner.x, corner.y );
|
||||||
}
|
}
|
||||||
|
@ -146,10 +144,10 @@ void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPo
|
||||||
polyshape.Append( corner.x, corner.y );
|
polyshape.Append( corner.x, corner.y );
|
||||||
|
|
||||||
// add left rounded end:
|
// add left rounded end:
|
||||||
for( int ii = 0; ii < numSegs / 2; ii++ )
|
for( int angle = 0; angle < 1800; angle += delta )
|
||||||
{
|
{
|
||||||
corner = wxPoint( 0, -radius );
|
corner = wxPoint( 0, -radius );
|
||||||
RotatePoint( &corner, delta * ii );
|
RotatePoint( &corner, angle );
|
||||||
polyshape.Append( corner.x, corner.y );
|
polyshape.Append( corner.x, corner.y );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,11 +155,8 @@ void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPo
|
||||||
corner = wxPoint( 0, radius );
|
corner = wxPoint( 0, radius );
|
||||||
polyshape.Append( corner.x, corner.y );
|
polyshape.Append( corner.x, corner.y );
|
||||||
|
|
||||||
// Now, clamp the polygonal shape (too big) with the segment bounding box
|
// Now trim the edges of the polygonal shape which will be slightly outside the
|
||||||
// the polygonal shape bbox equivalent to the segment has a too big height,
|
// track width.
|
||||||
// and the right width
|
|
||||||
if( correction > 1.0 )
|
|
||||||
{
|
|
||||||
SHAPE_POLY_SET bbox;
|
SHAPE_POLY_SET bbox;
|
||||||
bbox.NewOutline();
|
bbox.NewOutline();
|
||||||
// Build the bbox (a horizontal rectangle).
|
// Build the bbox (a horizontal rectangle).
|
||||||
|
@ -181,7 +176,6 @@ void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPo
|
||||||
polyshape.BooleanIntersection( bbox, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
polyshape.BooleanIntersection( bbox, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||||
// Note the final polygon is a simple, convex polygon with no hole
|
// Note the final polygon is a simple, convex polygon with no hole
|
||||||
// due to the shape of initial polygons
|
// due to the shape of initial polygons
|
||||||
}
|
|
||||||
|
|
||||||
// Rotate and move the polygon to its right location
|
// Rotate and move the polygon to its right location
|
||||||
polyshape.Rotate( delta_angle, VECTOR2I( 0, 0 ) );
|
polyshape.Rotate( delta_angle, VECTOR2I( 0, 0 ) );
|
||||||
|
@ -240,18 +234,13 @@ void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer, const
|
||||||
for( const wxPoint& corner : corners)
|
for( const wxPoint& corner : corners)
|
||||||
outline.Append( corner );
|
outline.Append( corner );
|
||||||
|
|
||||||
// These are small radius corners (of which there may be many), so peg the segs-per-circle
|
int numSegs = GetArcToSegmentCount( aCornerRadius, aError, 360.0 );
|
||||||
// to no more than 16.
|
|
||||||
int numSegs = std::max( GetArcToSegmentCount( aCornerRadius, aError, 360.0 ), 16 );
|
|
||||||
|
|
||||||
// To build the polygonal shape outside the actual shape, we use a bigger
|
// To build the polygonal shape outside the actual shape, we use a bigger
|
||||||
// radius to build rounded corners.
|
// radius to build rounded corners.
|
||||||
// However, the size of the shape is too large.
|
|
||||||
// so, we also clamp the polygonal shape with the bounding box
|
|
||||||
// of the initial shape.
|
|
||||||
|
|
||||||
double correction = GetCircletoPolyCorrectionFactor( numSegs );
|
int correction = GetCircleToPolyCorrection( aError );
|
||||||
int radius = aCornerRadius * correction; // make segments outside the circles
|
int radius = aCornerRadius + correction; // make segments outside the circles
|
||||||
outline.Inflate( radius, numSegs );
|
outline.Inflate( radius, numSegs );
|
||||||
|
|
||||||
if( correction > 1.0 )
|
if( correction > 1.0 )
|
||||||
|
@ -340,82 +329,12 @@ void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer, const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TransformSegmentToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoint aEnd,
|
|
||||||
int aError, int aWidth )
|
|
||||||
{
|
|
||||||
int radius = aWidth / 2;
|
|
||||||
wxPoint endp = aEnd - aStart; // end point coordinate for the same segment starting at (0,0)
|
|
||||||
wxPoint startp = aStart;
|
|
||||||
wxPoint corner;
|
|
||||||
VECTOR2I polypoint;
|
|
||||||
int numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ), 6 );
|
|
||||||
double correction = GetCircletoPolyCorrectionFactor( numSegs );
|
|
||||||
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
|
|
||||||
|
|
||||||
radius = KiROUND( radius * correction );
|
|
||||||
aCornerBuffer.NewOutline();
|
|
||||||
|
|
||||||
// normalize the position in order to have endp.x >= 0;
|
|
||||||
if( endp.x < 0 )
|
|
||||||
{
|
|
||||||
endp = aStart - aEnd;
|
|
||||||
startp = aEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
double delta_angle = ArcTangente( endp.y, endp.x ); // delta_angle is in 0.1 degrees
|
|
||||||
int seg_len = KiROUND( EuclideanNorm( endp ) );
|
|
||||||
|
|
||||||
// Compute the outlines of the segment, and creates a polygon
|
|
||||||
|
|
||||||
// add right rounded end:
|
|
||||||
for( int ii = 0; ii < 1800; ii += delta )
|
|
||||||
{
|
|
||||||
corner = wxPoint( 0, radius );
|
|
||||||
RotatePoint( &corner, ii );
|
|
||||||
corner.x += seg_len;
|
|
||||||
RotatePoint( &corner, -delta_angle );
|
|
||||||
corner += startp;
|
|
||||||
polypoint.x = corner.x;
|
|
||||||
polypoint.y = corner.y;
|
|
||||||
aCornerBuffer.Append( polypoint.x, polypoint.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finish arc:
|
|
||||||
corner = wxPoint( seg_len, -radius );
|
|
||||||
RotatePoint( &corner, -delta_angle );
|
|
||||||
corner += startp;
|
|
||||||
polypoint.x = corner.x;
|
|
||||||
polypoint.y = corner.y;
|
|
||||||
aCornerBuffer.Append( polypoint.x, polypoint.y );
|
|
||||||
|
|
||||||
// add left rounded end:
|
|
||||||
for( int ii = 0; ii < 1800; ii += delta )
|
|
||||||
{
|
|
||||||
corner = wxPoint( 0, -radius );
|
|
||||||
RotatePoint( &corner, ii );
|
|
||||||
RotatePoint( &corner, -delta_angle );
|
|
||||||
corner += startp;
|
|
||||||
polypoint.x = corner.x;
|
|
||||||
polypoint.y = corner.y;
|
|
||||||
aCornerBuffer.Append( polypoint.x, polypoint.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finish arc:
|
|
||||||
corner = wxPoint( 0, radius );
|
|
||||||
RotatePoint( &corner, -delta_angle );
|
|
||||||
corner += startp;
|
|
||||||
polypoint.x = corner.x;
|
|
||||||
polypoint.y = corner.y;
|
|
||||||
aCornerBuffer.Append( polypoint.x, polypoint.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCentre, wxPoint aStart,
|
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCentre, wxPoint aStart,
|
||||||
double aArcAngle, int aError, int aWidth )
|
double aArcAngle, int aError, int aWidth )
|
||||||
{
|
{
|
||||||
wxPoint arc_start, arc_end;
|
wxPoint arc_start, arc_end;
|
||||||
int dist = EuclideanNorm( aCentre - aStart );
|
int dist = EuclideanNorm( aCentre - aStart );
|
||||||
int numSegs = std::max( GetArcToSegmentCount( dist, aError, 360.0 ), 6 );
|
int numSegs = GetArcToSegmentCount( dist, aError, 360.0 );
|
||||||
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
|
int delta = 3600 / numSegs; // rotate angle in 0.1 degree
|
||||||
|
|
||||||
arc_end = arc_start = aStart;
|
arc_end = arc_start = aStart;
|
||||||
|
@ -437,12 +356,12 @@ void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCentre, wxPo
|
||||||
{
|
{
|
||||||
curr_end = arc_start;
|
curr_end = arc_start;
|
||||||
RotatePoint( &curr_end, aCentre, -ii );
|
RotatePoint( &curr_end, aCentre, -ii );
|
||||||
TransformSegmentToPolygon( aCornerBuffer, curr_start, curr_end, aError, aWidth );
|
TransformOvalToPolygon( aCornerBuffer, curr_start, curr_end, aWidth, aError );
|
||||||
curr_start = curr_end;
|
curr_start = curr_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( curr_end != arc_end )
|
if( curr_end != arc_end )
|
||||||
TransformSegmentToPolygon( aCornerBuffer, curr_end, arc_end, aError, aWidth );
|
TransformOvalToPolygon( aCornerBuffer, curr_end, arc_end, aWidth, aError );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,11 @@
|
||||||
#include <geometry/geometry_utils.h>
|
#include <geometry/geometry_utils.h>
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
|
|
||||||
// To approximate a circle by segments, a minimal seg count is mandatory
|
// To approximate a circle by segments, a minimal seg count is mandatory.
|
||||||
#define MIN_SEGCOUNT_FOR_CIRCLE 6
|
// Note that this is rarely used as the maxError constraint will yield a higher
|
||||||
|
// segment count on everything but very small circles. (Even a 0.125mm track
|
||||||
|
// with a 0.01mm maximum deviation yields 11 segments.)
|
||||||
|
#define MIN_SEGCOUNT_FOR_CIRCLE 8
|
||||||
|
|
||||||
int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree )
|
int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree )
|
||||||
{
|
{
|
||||||
|
@ -56,39 +59,35 @@ int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree )
|
||||||
|
|
||||||
int segCount = KiROUND( fabs( aArcAngleDegree ) / arc_increment );
|
int segCount = KiROUND( fabs( aArcAngleDegree ) / arc_increment );
|
||||||
|
|
||||||
// Ensure at least one segment is used (can happen for small arcs)
|
// Ensure at least two segments are used for algorithmic safety
|
||||||
return std::max( segCount, 1 );
|
return std::max( segCount, 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// When creating polygons to create a clearance polygonal area, the polygon must
|
// When creating polygons to create a clearance polygonal area, the polygon must
|
||||||
// be same or bigger than the original shape.
|
// be same or bigger than the original shape.
|
||||||
// Polygons are bigger if the original shape has arcs (round rectangles, ovals, circles...)
|
// Polygons are bigger if the original shape has arcs (round rectangles, ovals,
|
||||||
// In some cases (in fact only one: when building layer solder mask) modifying
|
// circles...). However, when building the solder mask layer modifying the shapes
|
||||||
// shapes when converting them to polygons is not acceptable (the modification
|
// when converting them to polygons is not acceptable (the modification can break
|
||||||
// can break calculations)
|
// calculations).
|
||||||
// so one can disable the shape expansion by calling KeepPolyInsideShape( true )
|
// So one can disable the shape expansion within a particular scope by allocating
|
||||||
// Important: calling KeepPolyInsideShape( false ) after calculations is
|
// a DISABLE_ARC_CORRECTION.
|
||||||
// mandatory to break oher calculations
|
|
||||||
static bool s_disable_arc_correction = false;
|
static bool s_disable_arc_correction = false;
|
||||||
|
|
||||||
// Enable (aInside = false) or disable (aInside = true) polygonal shape expansion
|
DISABLE_ARC_RADIUS_CORRECTION::DISABLE_ARC_RADIUS_CORRECTION()
|
||||||
// when converting pads shapes and other items shapes to polygons:
|
|
||||||
void DisableArcRadiusCorrection( bool aDisable )
|
|
||||||
{
|
{
|
||||||
s_disable_arc_correction = aDisable;
|
s_disable_arc_correction = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double GetCircletoPolyCorrectionFactor( int aSegCountforCircle )
|
DISABLE_ARC_RADIUS_CORRECTION::~DISABLE_ARC_RADIUS_CORRECTION()
|
||||||
{
|
{
|
||||||
/* calculates the coeff to compensate radius reduction of circle
|
s_disable_arc_correction = false;
|
||||||
* due to the segment approx.
|
}
|
||||||
* For a circle the min radius is radius * cos( 2PI / aSegCountforCircle / 2)
|
|
||||||
* this is the distance between the center and the middle of the segment.
|
int GetCircleToPolyCorrection( int aMaxError )
|
||||||
* therefore, to move the middle of the segment to the circle (distance = radius)
|
{
|
||||||
* the correctionFactor is 1 /cos( PI/aSegCountforCircle )
|
// Push all the error to the outside by increasing the radius
|
||||||
*/
|
return s_disable_arc_correction ? 0 : aMaxError;
|
||||||
aSegCountforCircle = std::max( MIN_SEGCOUNT_FOR_CIRCLE, aSegCountforCircle );
|
|
||||||
return s_disable_arc_correction ? 1.0 : 1.0 / cos( M_PI / aSegCountforCircle );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,8 @@ TSEGM_2_POLY_PRMS prms;
|
||||||
static void addTextSegmToPoly( int x0, int y0, int xf, int yf, void* aData )
|
static void addTextSegmToPoly( int x0, int y0, int xf, int yf, void* aData )
|
||||||
{
|
{
|
||||||
TSEGM_2_POLY_PRMS* prm = static_cast<TSEGM_2_POLY_PRMS*>( aData );
|
TSEGM_2_POLY_PRMS* prm = static_cast<TSEGM_2_POLY_PRMS*>( aData );
|
||||||
TransformSegmentToPolygon( *prm->m_cornerBuffer,
|
TransformOvalToPolygon( *prm->m_cornerBuffer, wxPoint( x0, y0 ), wxPoint( xf, yf ),
|
||||||
wxPoint( x0, y0 ), wxPoint( xf, yf ),
|
prm->m_textWidth, prm->m_error );
|
||||||
prm->m_error, prm->m_textWidth );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -296,7 +295,7 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygon( PCB_LAYER_ID aLayer,
|
||||||
if( board )
|
if( board )
|
||||||
maxError = board->GetDesignSettings().m_MaxError;
|
maxError = board->GetDesignSettings().m_MaxError;
|
||||||
|
|
||||||
int numSegs = std::max( GetArcToSegmentCount( GetMinThickness(), maxError, 360.0 ), 12 );
|
int numSegs = GetArcToSegmentCount( GetMinThickness(), maxError, 360.0 );
|
||||||
|
|
||||||
polys.InflateWithLinkedHoles( GetMinThickness()/2, numSegs, SHAPE_POLY_SET::PM_FAST );
|
polys.InflateWithLinkedHoles( GetMinThickness()/2, numSegs, SHAPE_POLY_SET::PM_FAST );
|
||||||
|
|
||||||
|
@ -420,10 +419,10 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
|
||||||
if( width > 0 )
|
if( width > 0 )
|
||||||
{
|
{
|
||||||
// Add in segments
|
// Add in segments
|
||||||
TransformSegmentToPolygon( aCornerBuffer, pts[0], pts[1], aError, width );
|
TransformOvalToPolygon( aCornerBuffer, pts[0], pts[1], width, aError );
|
||||||
TransformSegmentToPolygon( aCornerBuffer, pts[1], pts[2], aError, width );
|
TransformOvalToPolygon( aCornerBuffer, pts[1], pts[2], width, aError );
|
||||||
TransformSegmentToPolygon( aCornerBuffer, pts[2], pts[3], aError, width );
|
TransformOvalToPolygon( aCornerBuffer, pts[2], pts[3], width, aError );
|
||||||
TransformSegmentToPolygon( aCornerBuffer, pts[3], pts[0], aError, width );
|
TransformOvalToPolygon( aCornerBuffer, pts[3], pts[0], width, aError );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -473,7 +472,7 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
|
||||||
for( wxPoint pt2 : poly )
|
for( wxPoint pt2 : poly )
|
||||||
{
|
{
|
||||||
if( pt2 != pt1 )
|
if( pt2 != pt1 )
|
||||||
TransformSegmentToPolygon( aCornerBuffer, pt1, pt2, aError, width );
|
TransformOvalToPolygon( aCornerBuffer, pt1, pt2, width, aError );
|
||||||
|
|
||||||
pt1 = pt2;
|
pt1 = pt2;
|
||||||
}
|
}
|
||||||
|
@ -491,7 +490,7 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
|
||||||
if( width != 0 )
|
if( width != 0 )
|
||||||
{
|
{
|
||||||
for( unsigned ii = 1; ii < poly.size(); ii++ )
|
for( unsigned ii = 1; ii < poly.size(); ii++ )
|
||||||
TransformSegmentToPolygon( aCornerBuffer, poly[ii-1], poly[ii], aError, width );
|
TransformOvalToPolygon( aCornerBuffer, poly[ii-1], poly[ii], width, aError );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -511,7 +510,6 @@ void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
{
|
{
|
||||||
wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for tracks." );
|
wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for tracks." );
|
||||||
|
|
||||||
int width = m_Width + ( 2 * aClearanceValue );
|
|
||||||
|
|
||||||
switch( Type() )
|
switch( Type() )
|
||||||
{
|
{
|
||||||
|
@ -525,15 +523,20 @@ void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
case PCB_ARC_T:
|
case PCB_ARC_T:
|
||||||
{
|
{
|
||||||
const ARC* arc = static_cast<const ARC*>( this );
|
const ARC* arc = static_cast<const ARC*>( this );
|
||||||
|
int width = m_Width + ( 2 * aClearanceValue );
|
||||||
VECTOR2D center( arc->GetCenter() );
|
VECTOR2D center( arc->GetCenter() );
|
||||||
double arc_angle = arc->GetAngle();
|
double angle = arc->GetAngle();
|
||||||
TransformArcToPolygon( aCornerBuffer, wxPoint( center.x, center.y ),
|
|
||||||
GetStart(), arc_angle, aError, width );
|
TransformArcToPolygon( aCornerBuffer, (wxPoint) center, GetStart(), angle, aError, width );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
|
int width = m_Width + ( 2 * aClearanceValue );
|
||||||
|
|
||||||
TransformOvalToPolygon( aCornerBuffer, m_Start, m_End, width, aError );
|
TransformOvalToPolygon( aCornerBuffer, m_Start, m_End, width, aError );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -604,8 +607,7 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
{
|
{
|
||||||
int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ),
|
int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ),
|
||||||
pad_min_seg_per_circle_count );
|
pad_min_seg_per_circle_count );
|
||||||
double correction = GetCircletoPolyCorrectionFactor( numSegs );
|
int clearance = aClearanceValue + GetCircleToPolyCorrection( aError );
|
||||||
int clearance = KiROUND( aClearanceValue * correction );
|
|
||||||
outline.Inflate( clearance, numSegs );
|
outline.Inflate( clearance, numSegs );
|
||||||
// TODO: clamp the inflated polygon, because it is slightly too big:
|
// TODO: clamp the inflated polygon, because it is slightly too big:
|
||||||
// it was inflated by a value slightly too big to keep rounded corners
|
// it was inflated by a value slightly too big to keep rounded corners
|
||||||
|
@ -620,13 +622,10 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
case PAD_SHAPE_ROUNDRECT:
|
case PAD_SHAPE_ROUNDRECT:
|
||||||
{
|
{
|
||||||
int radius = GetRoundRectCornerRadius() + aClearanceValue;
|
int radius = GetRoundRectCornerRadius() + aClearanceValue;
|
||||||
int numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ),
|
int clearance = aClearanceValue + GetCircleToPolyCorrection( aError );
|
||||||
pad_min_seg_per_circle_count );
|
|
||||||
double correction = GetCircletoPolyCorrectionFactor( numSegs );
|
|
||||||
int clearance = KiROUND( aClearanceValue * correction );
|
|
||||||
wxSize shapesize( m_size );
|
wxSize shapesize( m_size );
|
||||||
|
|
||||||
radius = KiROUND( radius * correction );
|
radius = radius + GetCircleToPolyCorrection( aError );
|
||||||
shapesize.x += clearance * 2;
|
shapesize.x += clearance * 2;
|
||||||
shapesize.y += clearance * 2;
|
shapesize.y += clearance * 2;
|
||||||
bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
|
bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
|
||||||
|
@ -654,8 +653,7 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
{
|
{
|
||||||
int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ),
|
int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ),
|
||||||
pad_min_seg_per_circle_count );
|
pad_min_seg_per_circle_count );
|
||||||
double correction = GetCircletoPolyCorrectionFactor( numSegs );
|
int clearance = aClearanceValue + GetCircleToPolyCorrection( aError );
|
||||||
int clearance = KiROUND( aClearanceValue * correction );
|
|
||||||
|
|
||||||
outline.Inflate( clearance, numSegs );
|
outline.Inflate( clearance, numSegs );
|
||||||
}
|
}
|
||||||
|
@ -684,8 +682,8 @@ bool D_PAD::TransformHoleWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||||
|
|
||||||
const SHAPE_SEGMENT* seg = GetEffectiveHoleShape();
|
const SHAPE_SEGMENT* seg = GetEffectiveHoleShape();
|
||||||
|
|
||||||
TransformSegmentToPolygon( aCornerBuffer, (wxPoint) seg->GetSeg().A, (wxPoint) seg->GetSeg().B,
|
TransformOvalToPolygon( aCornerBuffer, (wxPoint) seg->GetSeg().A, (wxPoint) seg->GetSeg().B,
|
||||||
aError, seg->GetWidth() + aInflateValue * 2 );
|
seg->GetWidth() + aInflateValue * 2, aError );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1325,7 +1325,7 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SE
|
||||||
if( board )
|
if( board )
|
||||||
maxError = board->GetDesignSettings().m_MaxError;
|
maxError = board->GetDesignSettings().m_MaxError;
|
||||||
|
|
||||||
int segCount = std::max( GetArcToSegmentCount( aClearance, maxError, 360.0 ), 3 );
|
int segCount = GetArcToSegmentCount( aClearance, maxError, 360.0 );
|
||||||
polybuffer.Inflate( aClearance, segCount );
|
polybuffer.Inflate( aClearance, segCount );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -536,7 +536,7 @@ bool ConvertOutlineToPolygon( std::vector<DRAWSEGMENT*>& aSegList, SHAPE_POLY_SE
|
||||||
double angle = 3600.0;
|
double angle = 3600.0;
|
||||||
wxPoint start = center;
|
wxPoint start = center;
|
||||||
int radius = graphic->GetRadius();
|
int radius = graphic->GetRadius();
|
||||||
int steps = std::max<int>( 4, GetArcToSegmentCount( radius, aTolerance, 360.0 ) );
|
int steps = GetArcToSegmentCount( radius, aTolerance, 360.0 );
|
||||||
wxPoint nextPt;
|
wxPoint nextPt;
|
||||||
|
|
||||||
start.x += radius;
|
start.x += radius;
|
||||||
|
|
|
@ -1252,39 +1252,45 @@ void DRC::setTransitions()
|
||||||
const int UI_EPSILON = Mils2iu( 5 );
|
const int UI_EPSILON = Mils2iu( 5 );
|
||||||
|
|
||||||
|
|
||||||
wxPoint DRC::GetLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone )
|
wxPoint DRC::GetLocation( PCB_LAYER_ID aLayer, TRACK* aTrack, ZONE_CONTAINER* aZone )
|
||||||
{
|
{
|
||||||
SHAPE_POLY_SET* conflictOutline = nullptr;
|
SHAPE_POLY_SET* zonePoly = nullptr;
|
||||||
|
|
||||||
PCB_LAYER_ID l = aTrack->GetLayer();
|
if( aZone->IsFilled() && aZone->HasFilledPolysForLayer( aLayer ) )
|
||||||
|
zonePoly = const_cast<SHAPE_POLY_SET*>( &aZone->GetFilledPolysList( aLayer ) );
|
||||||
|
|
||||||
if( aConflictZone->IsFilled() && aConflictZone->HasFilledPolysForLayer( l ) )
|
if( !zonePoly || zonePoly->IsEmpty() )
|
||||||
conflictOutline = const_cast<SHAPE_POLY_SET*>( &aConflictZone->GetFilledPolysList( l ) );
|
zonePoly = aZone->Outline();
|
||||||
|
|
||||||
if( !conflictOutline || conflictOutline->IsEmpty() )
|
SEG trackSeg( aTrack->GetStart(), aTrack->GetEnd() );
|
||||||
conflictOutline = aConflictZone->Outline();
|
SEG::ecoord closestDist_sq = VECTOR2I::ECOORD_MAX;
|
||||||
|
SEG closestSeg;
|
||||||
|
|
||||||
wxPoint pt1 = aTrack->GetPosition();
|
for( auto it = zonePoly->CIterateSegments( 0, -1, true ); it; it++ )
|
||||||
wxPoint pt2 = aTrack->GetEnd();
|
|
||||||
|
|
||||||
// If the mid-point is in the zone, then that's a fine place for the marker
|
|
||||||
if( conflictOutline->SquaredDistance( ( pt1 + pt2 ) / 2 ) == 0 )
|
|
||||||
return ( pt1 + pt2 ) / 2;
|
|
||||||
|
|
||||||
// Otherwise do a binary search for a "good enough" marker location
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
while( GetLineLength( pt1, pt2 ) > UI_EPSILON )
|
SEG::ecoord dist_sq = trackSeg.SquaredDistance( *it );
|
||||||
|
|
||||||
|
if( dist_sq < closestDist_sq )
|
||||||
{
|
{
|
||||||
if( conflictOutline->SquaredDistance( pt1 ) < conflictOutline->SquaredDistance( pt2 ) )
|
closestDist_sq = dist_sq;
|
||||||
|
closestSeg = *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VECTOR2I pt1 = closestSeg.A;
|
||||||
|
VECTOR2I pt2 = closestSeg.B;
|
||||||
|
|
||||||
|
// Do a binary search for a "good enough" marker location
|
||||||
|
while( GetLineLength( (wxPoint) pt1, (wxPoint) pt2 ) > UI_EPSILON )
|
||||||
|
{
|
||||||
|
if( trackSeg.SquaredDistance( pt1 ) < trackSeg.SquaredDistance( pt2 ) )
|
||||||
pt2 = ( pt1 + pt2 ) / 2;
|
pt2 = ( pt1 + pt2 ) / 2;
|
||||||
else
|
else
|
||||||
pt1 = ( pt1 + pt2 ) / 2;
|
pt1 = ( pt1 + pt2 ) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once we're within UI_EPSILON pt1 and pt2 are "equivalent"
|
// Once we're within UI_EPSILON pt1 and pt2 are "equivalent"
|
||||||
return pt1;
|
return (wxPoint) pt1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -246,8 +246,8 @@ public:
|
||||||
/**
|
/**
|
||||||
* Fetches a reasonable point for marking a violoation between two non-point objects.
|
* Fetches a reasonable point for marking a violoation between two non-point objects.
|
||||||
*/
|
*/
|
||||||
static wxPoint GetLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone );
|
static wxPoint GetLocation( PCB_LAYER_ID aLayer, TRACK* aTrack, ZONE_CONTAINER* aZone );
|
||||||
static wxPoint GetLocation( TRACK* aTrack, const SEG& aConflictSeg );
|
static wxPoint GetLocation( TRACK* aTrack, const SEG& aSeg );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a dialog and prompts the user, then if a test run button is
|
* Open a dialog and prompts the user, then if a test run button is
|
||||||
|
|
|
@ -443,9 +443,9 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
/* Phase 3: test DRC with copper zones */
|
/* Phase 3: test DRC with copper zones */
|
||||||
/***************************************/
|
/***************************************/
|
||||||
// Can be *very* time consumming.
|
// Can be *very* time consumming.
|
||||||
|
|
||||||
if( aTestZones )
|
if( aTestZones )
|
||||||
{
|
{
|
||||||
|
|
||||||
for( ZONE_CONTAINER* zone : m_pcb->Zones() )
|
for( ZONE_CONTAINER* zone : m_pcb->Zones() )
|
||||||
{
|
{
|
||||||
if( !zone->GetLayerSet().test( aLayer ) || zone->GetIsKeepout() )
|
if( !zone->GetLayerSet().test( aLayer ) || zone->GetIsKeepout() )
|
||||||
|
@ -474,7 +474,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( aRefSeg, zone );
|
drcItem->SetItems( aRefSeg, zone );
|
||||||
|
|
||||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, zone ) );
|
MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aLayer, aRefSeg, zone ) );
|
||||||
addMarkerToPcb( aCommit, marker );
|
addMarkerToPcb( aCommit, marker );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,9 @@ bool DRC_KEEPOUT_TESTER::checkTracksAndVias()
|
||||||
if( segm->Type() == PCB_TRACE_T && ( m_keepoutFlags & DISALLOW_TRACKS ) != 0 )
|
if( segm->Type() == PCB_TRACE_T && ( m_keepoutFlags & DISALLOW_TRACKS ) != 0 )
|
||||||
{
|
{
|
||||||
// Ignore if the keepout zone is not on the same layer
|
// Ignore if the keepout zone is not on the same layer
|
||||||
if( !m_zone->IsOnLayer( segm->GetLayer() ) )
|
PCB_LAYER_ID layer = segm->GetLayer();
|
||||||
|
|
||||||
|
if( !m_zone->IsOnLayer( layer ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SEG trackSeg( segm->GetStart(), segm->GetEnd() );
|
SEG trackSeg( segm->GetStart(), segm->GetEnd() );
|
||||||
|
@ -103,7 +105,7 @@ bool DRC_KEEPOUT_TESTER::checkTracksAndVias()
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( segm, m_zone );
|
drcItem->SetItems( segm, m_zone );
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, DRC::GetLocation( segm, m_zone ) ) );
|
HandleMarker( new MARKER_PCB( drcItem, DRC::GetLocation( layer, segm, m_zone ) ) );
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +145,7 @@ bool DRC_KEEPOUT_TESTER::checkTracksAndVias()
|
||||||
drcItem->SetErrorMessage( m_msg );
|
drcItem->SetErrorMessage( m_msg );
|
||||||
drcItem->SetItems( segm, m_zone );
|
drcItem->SetItems( segm, m_zone );
|
||||||
|
|
||||||
HandleMarker( new MARKER_PCB( drcItem, DRC::GetLocation( segm, m_zone ) ) );
|
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1295,11 +1295,8 @@ ZONE_CONTAINER* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
|
||||||
double radius = sqrt( pow( center.x - kicad_x( v1.x ), 2 )
|
double radius = sqrt( pow( center.x - kicad_x( v1.x ), 2 )
|
||||||
+ pow( center.y - kicad_y( v1.y ), 2 ) );
|
+ pow( center.y - kicad_y( v1.y ), 2 ) );
|
||||||
|
|
||||||
// If we are curving, we need at least 2 segments otherwise
|
int segCount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, *v1.curve );
|
||||||
// delta_angle == angle
|
double delta_angle = angle / segCount;
|
||||||
double delta_angle = angle / std::max(
|
|
||||||
2, GetArcToSegmentCount( KiROUND( radius ),
|
|
||||||
ARC_HIGH_DEF, *v1.curve ) - 1 );
|
|
||||||
|
|
||||||
for( double a = end_angle + angle;
|
for( double a = end_angle + angle;
|
||||||
fabs( a - end_angle ) > fabs( delta_angle );
|
fabs( a - end_angle ) > fabs( delta_angle );
|
||||||
|
@ -1959,12 +1956,7 @@ void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const
|
||||||
if( KiROUND( radius ) == 0 )
|
if( KiROUND( radius ) == 0 )
|
||||||
radius = 1.0;
|
radius = 1.0;
|
||||||
|
|
||||||
int segCount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, *v1.curve ) - 1;
|
int segCount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, *v1.curve );
|
||||||
|
|
||||||
// If we are curving, we need at least 2 segments otherwise delta == angle
|
|
||||||
if( segCount < 2 )
|
|
||||||
segCount = 2;
|
|
||||||
|
|
||||||
double delta = angle / segCount;
|
double delta = angle / segCount;
|
||||||
|
|
||||||
for( double a = end_angle + angle; fabs( a - end_angle ) > fabs( delta ); a -= delta )
|
for( double a = end_angle + angle; fabs( a - end_angle ) > fabs( delta ); a -= delta )
|
||||||
|
@ -2295,12 +2287,8 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
|
||||||
radius = sqrt( pow( center.x - kicad_x( w.x1 ), 2 ) +
|
radius = sqrt( pow( center.x - kicad_x( w.x1 ), 2 ) +
|
||||||
pow( center.y - kicad_y( w.y1 ), 2 ) );
|
pow( center.y - kicad_y( w.y1 ), 2 ) );
|
||||||
|
|
||||||
// If we are curving, we need at least 2 segments otherwise
|
int segs = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, *w.curve );
|
||||||
// delta_angle == angle
|
delta_angle = angle / segs;
|
||||||
int segments = std::max( 2, GetArcToSegmentCount( KiROUND( radius ),
|
|
||||||
ARC_HIGH_DEF,
|
|
||||||
*w.curve ) - 1 );
|
|
||||||
delta_angle = angle / segments;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while( fabs( angle ) > fabs( delta_angle ) )
|
while( fabs( angle ) > fabs( delta_angle ) )
|
||||||
|
|
|
@ -671,8 +671,7 @@ static void export_vrml_polygon( MODEL_VRML& aModel, LAYER_NUM layer,
|
||||||
|
|
||||||
if( aOutline->GetWidth() )
|
if( aOutline->GetWidth() )
|
||||||
{
|
{
|
||||||
int numSegs = std::max(
|
int numSegs = GetArcToSegmentCount( aOutline->GetWidth() / 2, ARC_HIGH_DEF, 360.0 );
|
||||||
GetArcToSegmentCount( aOutline->GetWidth() / 2, ARC_HIGH_DEF, 360.0 ), 6 );
|
|
||||||
shape.Inflate( aOutline->GetWidth() / 2, numSegs );
|
shape.Inflate( aOutline->GetWidth() / 2, numSegs );
|
||||||
shape.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
shape.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ static void gen_arc( std::vector <wxPoint>& aBuffer,
|
||||||
{
|
{
|
||||||
auto first_point = aStartPoint - aCenter;
|
auto first_point = aStartPoint - aCenter;
|
||||||
auto radius = KiROUND( EuclideanNorm( first_point ) );
|
auto radius = KiROUND( EuclideanNorm( first_point ) );
|
||||||
int seg_count = std::max( GetArcToSegmentCount( radius, ARC_HIGH_DEF, a_ArcAngle / 10.0 ), 3 );
|
int seg_count = GetArcToSegmentCount( radius, ARC_HIGH_DEF, a_ArcAngle / 10.0 );
|
||||||
|
|
||||||
double increment_angle = (double) a_ArcAngle * M_PI / 1800 / seg_count;
|
double increment_angle = (double) a_ArcAngle * M_PI / 1800 / seg_count;
|
||||||
|
|
||||||
|
|
|
@ -344,7 +344,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
||||||
// Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
|
// Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
|
||||||
// which can create bad shapes if margin.x is < 0
|
// which can create bad shapes if margin.x is < 0
|
||||||
int maxError = aBoard->GetDesignSettings().m_MaxError;
|
int maxError = aBoard->GetDesignSettings().m_MaxError;
|
||||||
int numSegs = std::max( GetArcToSegmentCount( margin.x, maxError, 360.0 ), 6 );
|
int numSegs = GetArcToSegmentCount( margin.x, maxError, 360.0 );
|
||||||
shape.InflateWithLinkedHoles( margin.x, numSegs, SHAPE_POLY_SET::PM_FAST );
|
shape.InflateWithLinkedHoles( margin.x, numSegs, SHAPE_POLY_SET::PM_FAST );
|
||||||
dummy.DeletePrimitivesList();
|
dummy.DeletePrimitivesList();
|
||||||
dummy.AddPrimitivePoly( shape, 0 );
|
dummy.AddPrimitivePoly( shape, 0 );
|
||||||
|
@ -781,9 +781,6 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||||
// They do not have a solder Mask margin, because they are graphic items
|
// They do not have a solder Mask margin, because they are graphic items
|
||||||
// on this layer (like logos), not actually areas around pads.
|
// on this layer (like logos), not actually areas around pads.
|
||||||
|
|
||||||
// Normal mode to generate polygons from shapes with arcs, if any:
|
|
||||||
DisableArcRadiusCorrection( false );
|
|
||||||
|
|
||||||
itemplotter.PlotBoardGraphicItems();
|
itemplotter.PlotBoardGraphicItems();
|
||||||
|
|
||||||
for( auto module : aBoard->Modules() )
|
for( auto module : aBoard->Modules() )
|
||||||
|
@ -812,9 +809,9 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||||
#if NEW_ALGO
|
#if NEW_ALGO
|
||||||
// Generate polygons with arcs inside the shape or exact shape
|
// Generate polygons with arcs inside the shape or exact shape
|
||||||
// to minimize shape changes created by arc to segment size correction.
|
// to minimize shape changes created by arc to segment size correction.
|
||||||
DisableArcRadiusCorrection( true );
|
DISABLE_ARC_RADIUS_CORRECTION disabler;
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
// Plot pads
|
// Plot pads
|
||||||
for( auto module : aBoard->Modules() )
|
for( auto module : aBoard->Modules() )
|
||||||
{
|
{
|
||||||
|
@ -876,7 +873,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxError = aBoard->GetDesignSettings().m_MaxError;
|
int maxError = aBoard->GetDesignSettings().m_MaxError;
|
||||||
int numSegs = std::max( GetArcToSegmentCount( inflate, maxError, 360.0 ), 12 );
|
int numSegs = GetArcToSegmentCount( inflate, maxError, 360.0 );
|
||||||
|
|
||||||
// Merge all polygons: After deflating, not merged (not overlapping) polygons
|
// Merge all polygons: After deflating, not merged (not overlapping) polygons
|
||||||
// will have the initial shape (with perhaps small changes due to deflating transform)
|
// will have the initial shape (with perhaps small changes due to deflating transform)
|
||||||
|
@ -885,9 +882,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||||
|
|
||||||
// Restore initial settings:
|
// Restore initial settings:
|
||||||
aBoard->GetDesignSettings().m_MaxError = currMaxError;
|
aBoard->GetDesignSettings().m_MaxError = currMaxError;
|
||||||
|
}
|
||||||
// Restore normal option to build polygons from item shapes:
|
|
||||||
DisableArcRadiusCorrection( false );
|
|
||||||
|
|
||||||
#if !NEW_ALGO
|
#if !NEW_ALGO
|
||||||
// To avoid a lot of code, use a ZONE_CONTAINER to handle and plot polygons, because our
|
// To avoid a lot of code, use a ZONE_CONTAINER to handle and plot polygons, because our
|
||||||
|
|
|
@ -82,8 +82,7 @@ ZONE_FILLER::ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit ) :
|
||||||
m_brdOutlinesValid( false ),
|
m_brdOutlinesValid( false ),
|
||||||
m_commit( aCommit ),
|
m_commit( aCommit ),
|
||||||
m_progressReporter( nullptr ),
|
m_progressReporter( nullptr ),
|
||||||
m_high_def( 9 ),
|
m_maxError( ARC_HIGH_DEF )
|
||||||
m_low_def( 6 )
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,7 +469,7 @@ void ZONE_FILLER::addKnockout( D_PAD* aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE
|
||||||
if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
|
if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||||
{
|
{
|
||||||
SHAPE_POLY_SET poly;
|
SHAPE_POLY_SET poly;
|
||||||
aPad->TransformShapeWithClearanceToPolygon( poly, aLayer, aGap, m_high_def );
|
aPad->TransformShapeWithClearanceToPolygon( poly, aLayer, aGap, m_maxError );
|
||||||
|
|
||||||
// the pad shape in zone can be its convex hull or the shape itself
|
// the pad shape in zone can be its convex hull or the shape itself
|
||||||
if( aPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
if( aPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||||
|
@ -488,14 +487,7 @@ void ZONE_FILLER::addKnockout( D_PAD* aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Optimizing polygon vertex count: the high definition is used for round
|
aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError );
|
||||||
// and oval pads (pads with large arcs) but low def for other shapes (with
|
|
||||||
// small arcs)
|
|
||||||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE || aPad->GetShape() == PAD_SHAPE_OVAL ||
|
|
||||||
( aPad->GetShape() == PAD_SHAPE_ROUNDRECT && aPad->GetRoundRectRadiusRatio() > 0.4 ) )
|
|
||||||
aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_high_def );
|
|
||||||
else
|
|
||||||
aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_low_def );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +504,7 @@ void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap,
|
||||||
case PCB_LINE_T:
|
case PCB_LINE_T:
|
||||||
{
|
{
|
||||||
DRAWSEGMENT* seg = (DRAWSEGMENT*) aItem;
|
DRAWSEGMENT* seg = (DRAWSEGMENT*) aItem;
|
||||||
seg->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_high_def,
|
seg->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
|
||||||
aIgnoreLineWidth );
|
aIgnoreLineWidth );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -525,7 +517,7 @@ void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap,
|
||||||
case PCB_MODULE_EDGE_T:
|
case PCB_MODULE_EDGE_T:
|
||||||
{
|
{
|
||||||
EDGE_MODULE* edge = (EDGE_MODULE*) aItem;
|
EDGE_MODULE* edge = (EDGE_MODULE*) aItem;
|
||||||
edge->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_high_def,
|
edge->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError,
|
||||||
aIgnoreLineWidth );
|
aIgnoreLineWidth );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -674,17 +666,17 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
|
||||||
|
|
||||||
if( !via->IsPadOnLayer( aLayer ) )
|
if( !via->IsPadOnLayer( aLayer ) )
|
||||||
{
|
{
|
||||||
TransformCircleToPolygon( aHoles, via->GetPosition(),
|
int radius = via->GetDrillValue() / 2 + bds.GetHolePlatingThickness() + gap;
|
||||||
( via->GetDrillValue() + 1 ) / 2 + gap, m_low_def );
|
TransformCircleToPolygon( aHoles, via->GetPosition(), radius, m_maxError );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
via->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap, m_low_def );
|
via->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap, m_maxError );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
track->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap, m_low_def );
|
track->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap, m_maxError );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -780,15 +772,14 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_I
|
||||||
SHAPE_POLY_SET& aRawPolys,
|
SHAPE_POLY_SET& aRawPolys,
|
||||||
SHAPE_POLY_SET& aFinalPolys )
|
SHAPE_POLY_SET& aFinalPolys )
|
||||||
{
|
{
|
||||||
m_high_def = m_board->GetDesignSettings().m_MaxError;
|
m_maxError = m_board->GetDesignSettings().m_MaxError;
|
||||||
m_low_def = std::min( ARC_LOW_DEF, int( m_high_def * 1.5 ) ); // Reasonable value
|
|
||||||
|
|
||||||
// Features which are min_width should survive pruning; features that are *less* than
|
// Features which are min_width should survive pruning; features that are *less* than
|
||||||
// min_width should not. Therefore we subtract epsilon from the min_width when
|
// min_width should not. Therefore we subtract epsilon from the min_width when
|
||||||
// deflating/inflating.
|
// deflating/inflating.
|
||||||
int half_min_width = aZone->GetMinThickness() / 2;
|
int half_min_width = aZone->GetMinThickness() / 2;
|
||||||
int epsilon = Millimeter2iu( 0.001 );
|
int epsilon = Millimeter2iu( 0.001 );
|
||||||
int numSegs = std::max( GetArcToSegmentCount( half_min_width, m_high_def, 360.0 ), 6 );
|
int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
|
||||||
|
|
||||||
SHAPE_POLY_SET::CORNER_STRATEGY cornerStrategy;
|
SHAPE_POLY_SET::CORNER_STRATEGY cornerStrategy;
|
||||||
|
|
||||||
|
@ -974,7 +965,7 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
|
||||||
// deflating/inflating.
|
// deflating/inflating.
|
||||||
int half_min_width = aZone->GetMinThickness() / 2;
|
int half_min_width = aZone->GetMinThickness() / 2;
|
||||||
int epsilon = Millimeter2iu( 0.001 );
|
int epsilon = Millimeter2iu( 0.001 );
|
||||||
int numSegs = std::max( GetArcToSegmentCount( half_min_width, m_high_def, 360.0 ), 6 );
|
int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
|
||||||
|
|
||||||
if( m_brdOutlinesValid )
|
if( m_brdOutlinesValid )
|
||||||
smoothedPoly.BooleanIntersection( m_boardOutline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
smoothedPoly.BooleanIntersection( m_boardOutline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||||
|
|
|
@ -115,14 +115,7 @@ private:
|
||||||
WX_PROGRESS_REPORTER* m_progressReporter;
|
WX_PROGRESS_REPORTER* m_progressReporter;
|
||||||
std::unique_ptr<WX_PROGRESS_REPORTER> m_uniqueReporter;
|
std::unique_ptr<WX_PROGRESS_REPORTER> m_uniqueReporter;
|
||||||
|
|
||||||
// m_high_def can be used to define a high definition arc to polygon approximation
|
int m_maxError;
|
||||||
int m_high_def;
|
|
||||||
|
|
||||||
// m_low_def can be used to define a low definition arc to polygon approximation
|
|
||||||
// Used when converting some pad shapes that can accept lower resolution, vias and track ends.
|
|
||||||
// Rect pads use m_low_def to reduce the number of segments. For these shapes a low def
|
|
||||||
// gives a good shape, because the arc is small (90 degrees) and a small part of the shape.
|
|
||||||
int m_low_def;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue