Cleanup pad geometry handling.
There were a lot of plotters, exporters, etc. that were rolling their own implementations. This also introduces a lazily-built set of SHAPE objects for doing collision detection and some forms of rendering (and later DRC).
This commit is contained in:
parent
c57c21f577
commit
d01b29ab37
|
@ -603,21 +603,10 @@ class BOARD_ADAPTER
|
|||
SHAPE_POLY_SET &aCornerBuffer,
|
||||
int aWidth) const;
|
||||
|
||||
void transformPadsShapesWithClearanceToPolygon( const PADS &aPads,
|
||||
PCB_LAYER_ID aLayer,
|
||||
SHAPE_POLY_SET &aCornerBuffer,
|
||||
int aInflateValue,
|
||||
bool aSkipNPTHPadsWihNoCopper) const;
|
||||
|
||||
void transformGraphicModuleEdgeToPolygonSet( const MODULE *aModule,
|
||||
PCB_LAYER_ID aLayer,
|
||||
SHAPE_POLY_SET& aCornerBuffer ) const;
|
||||
|
||||
void buildPadShapePolygon( const D_PAD *aPad,
|
||||
SHAPE_POLY_SET &aCornerBuffer,
|
||||
wxSize aInflateValue ) const;
|
||||
|
||||
|
||||
public:
|
||||
SFVEC3D m_BgColorBot; ///< background bottom color
|
||||
SFVEC3D m_BgColorTop; ///< background top color
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include "../3d_rendering/3d_render_raytracing/shapes2D/cring2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/cfilledcircle2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/croundsegment2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/cpolygon4pts2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/ctriangle2d.h"
|
||||
#include <board_adapter.h>
|
||||
#include <class_board.h>
|
||||
|
@ -45,13 +44,15 @@
|
|||
#include <class_text_mod.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <trigo.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/shape_circle.h>
|
||||
#include <geometry/shape_simple.h>
|
||||
#include <gr_text.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
// These variables are parameters used in addTextSegmToContainer.
|
||||
// But addTextSegmToContainer is a call-back function,
|
||||
// so we cannot send them as arguments.
|
||||
|
@ -310,261 +311,89 @@ void BOARD_ADAPTER::createNewTrack( const TRACK* aTrack, CGENERICCONTAINER2D *aD
|
|||
}
|
||||
|
||||
|
||||
// Based on:
|
||||
// void D_PAD:: TransformShapeWithClearanceToPolygon(
|
||||
// board_items_to_polygon_shape_transform.cpp
|
||||
void BOARD_ADAPTER::createNewPadWithClearance( const D_PAD* aPad,
|
||||
CGENERICCONTAINER2D *aDstContainer,
|
||||
wxSize aClearanceValue ) const
|
||||
{
|
||||
// note: for most of shapes, aClearanceValue.x = aClearanceValue.y
|
||||
// only rectangular and oval shapes can have different values
|
||||
// when drawn on the solder paste layer, because we can have a margin that is a
|
||||
// percent of pad size
|
||||
const int dx = (aPad->GetSize().x / 2) + aClearanceValue.x;
|
||||
const int dy = (aPad->GetSize().y / 2) + aClearanceValue.y;
|
||||
SHAPE_POLY_SET poly;
|
||||
|
||||
if( !dx || !dy )
|
||||
if( aClearanceValue.x != aClearanceValue.y )
|
||||
{
|
||||
wxLogTrace( m_logTrace,
|
||||
wxT( "BOARD_ADAPTER::createNewPadWithClearance - found an invalid pad" ) );
|
||||
|
||||
return;
|
||||
// Our shape-based builder can't handle differing x:y clearance values (which
|
||||
// get generated when relative paste margin is used with an oblong pad). So
|
||||
// we fake a larger pad and run the general-purpose polygon builder on it.
|
||||
D_PAD dummy( *aPad );
|
||||
dummy.SetSize( aPad->GetSize() + aClearanceValue + aClearanceValue );
|
||||
dummy.TransformShapeWithClearanceToPolygon( poly, 0 );
|
||||
}
|
||||
|
||||
wxPoint PadShapePos = aPad->ShapePos(); // Note: for pad having a shape offset,
|
||||
// the pad position is NOT the shape position
|
||||
|
||||
switch( aPad->GetShape() )
|
||||
else
|
||||
{
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
{
|
||||
const float radius = dx * m_biuTo3Dunits;
|
||||
|
||||
const SFVEC2F center( PadShapePos.x * m_biuTo3Dunits,
|
||||
-PadShapePos.y * m_biuTo3Dunits );
|
||||
|
||||
aDstContainer->Add( new CFILLEDCIRCLE2D( center, radius, *aPad ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_OVAL:
|
||||
{
|
||||
if( dx == dy )
|
||||
for( const std::shared_ptr<SHAPE>& shape : aPad->GetEffectiveShapes() )
|
||||
{
|
||||
// The segment object cannot store start and end the same position,
|
||||
// so add a circle instead
|
||||
const float radius = dx * m_biuTo3Dunits;
|
||||
|
||||
const SFVEC2F center( PadShapePos.x * m_biuTo3Dunits,
|
||||
-PadShapePos.y * m_biuTo3Dunits );
|
||||
|
||||
aDstContainer->Add( new CFILLEDCIRCLE2D( center, radius, *aPad ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// An oval pad has the same shape as a segment with rounded ends
|
||||
|
||||
int iwidth;
|
||||
wxPoint shape_offset = wxPoint( 0, 0 );
|
||||
|
||||
if( dy > dx ) // Oval pad X/Y ratio for choosing translation axis
|
||||
switch( shape->Type() )
|
||||
{
|
||||
shape_offset.y = dy - dx;
|
||||
iwidth = dx * 2;
|
||||
}
|
||||
else //if( dy < dx )
|
||||
case SH_SEGMENT:
|
||||
{
|
||||
shape_offset.x = dy - dx;
|
||||
iwidth = dy * 2;
|
||||
}
|
||||
const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shape.get();
|
||||
const SFVEC2F start3DU( seg->GetSeg().A.x * m_biuTo3Dunits,
|
||||
-seg->GetSeg().A.y * m_biuTo3Dunits );
|
||||
const SFVEC2F end3DU ( seg->GetSeg().B.x * m_biuTo3Dunits,
|
||||
-seg->GetSeg().B.y * m_biuTo3Dunits );
|
||||
const int width = seg->GetWidth() + aClearanceValue.x * 2;
|
||||
|
||||
RotatePoint( &shape_offset, aPad->GetOrientation() );
|
||||
|
||||
const wxPoint start = PadShapePos - shape_offset;
|
||||
const wxPoint end = PadShapePos + shape_offset;
|
||||
|
||||
const SFVEC2F start3DU( start.x * m_biuTo3Dunits, -start.y * m_biuTo3Dunits );
|
||||
const SFVEC2F end3DU ( end.x * m_biuTo3Dunits, -end.y * m_biuTo3Dunits );
|
||||
|
||||
// Cannot add segments that have the same start and end point
|
||||
if( Is_segment_a_circle( start3DU, end3DU ) )
|
||||
{
|
||||
aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
|
||||
(iwidth / 2) * m_biuTo3Dunits,
|
||||
*aPad ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
|
||||
iwidth * m_biuTo3Dunits,
|
||||
*aPad ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_RECT:
|
||||
{
|
||||
// see pcbnew/board_items_to_polygon_shape_transform.cpp
|
||||
wxPoint corners[4];
|
||||
bool drawOutline;
|
||||
|
||||
// For aClearanceValue.x == aClearanceValue.y and > 0 we use the pad shape
|
||||
// and draw outlines with thicknes = aClearanceValue.
|
||||
// Otherwise we draw only the inflated/deflated shape
|
||||
if( aClearanceValue.x > 0 && aClearanceValue.x == aClearanceValue.y )
|
||||
{
|
||||
drawOutline = true;
|
||||
aPad->BuildPadPolygon( corners, wxSize( 0, 0 ), aPad->GetOrientation() );
|
||||
}
|
||||
else
|
||||
{
|
||||
drawOutline = false;
|
||||
aPad->BuildPadPolygon( corners, aClearanceValue, aPad->GetOrientation() );
|
||||
}
|
||||
|
||||
SFVEC2F corners3DU[4];
|
||||
|
||||
// Note: for pad having a shape offset,
|
||||
// the pad position is NOT the shape position
|
||||
for( unsigned int ii = 0; ii < 4; ++ii )
|
||||
{
|
||||
corners[ii] += aPad->ShapePos(); // Shift origin to position
|
||||
|
||||
corners3DU[ii] = SFVEC2F( corners[ii].x * m_biuTo3Dunits,
|
||||
-corners[ii].y * m_biuTo3Dunits );
|
||||
}
|
||||
|
||||
|
||||
// Learn more at:
|
||||
// https://lists.launchpad.net/kicad-developers/msg18729.html
|
||||
|
||||
// Add the PAD polygon
|
||||
aDstContainer->Add( new CPOLYGON4PTS2D( corners3DU[0],
|
||||
corners3DU[1],
|
||||
corners3DU[2],
|
||||
corners3DU[3],
|
||||
*aPad ) );
|
||||
|
||||
// Add the PAD contours
|
||||
// Round segments cannot have 0-length elements, so we approximate them
|
||||
// as a small circle
|
||||
if( drawOutline )
|
||||
{
|
||||
for( int i = 1; i <= 4; i++ )
|
||||
{
|
||||
if( Is_segment_a_circle( corners3DU[i - 1], corners3DU[i & 3] ) )
|
||||
// Cannot add segments that have the same start and end point
|
||||
if( Is_segment_a_circle( start3DU, end3DU ) )
|
||||
{
|
||||
aDstContainer->Add( new CFILLEDCIRCLE2D( corners3DU[i - 1],
|
||||
aClearanceValue.x * m_biuTo3Dunits,
|
||||
*aPad ) );
|
||||
aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
|
||||
( width / 2) * m_biuTo3Dunits,
|
||||
*aPad ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aDstContainer->Add( new CROUNDSEGMENT2D( corners3DU[i - 1],
|
||||
corners3DU[i & 3],
|
||||
aClearanceValue.x * 2.0f * m_biuTo3Dunits,
|
||||
aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
|
||||
width * m_biuTo3Dunits,
|
||||
*aPad ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
{
|
||||
wxSize shapesize( aPad->GetSize() );
|
||||
shapesize.x += aClearanceValue.x * 2;
|
||||
shapesize.y += aClearanceValue.y * 2;
|
||||
|
||||
int rounding_radius = aPad->GetRoundRectCornerRadius( shapesize );
|
||||
|
||||
wxPoint corners[4];
|
||||
|
||||
GetRoundRectCornerCenters( corners,
|
||||
rounding_radius,
|
||||
PadShapePos,
|
||||
shapesize,
|
||||
aPad->GetOrientation() );
|
||||
|
||||
SFVEC2F corners3DU[4];
|
||||
|
||||
for( unsigned int ii = 0; ii < 4; ++ii )
|
||||
corners3DU[ii] = SFVEC2F( corners[ii].x * m_biuTo3Dunits,
|
||||
-corners[ii].y * m_biuTo3Dunits );
|
||||
|
||||
// Add the PAD polygon (For some reason the corners need
|
||||
// to be inverted to display with the correctly orientation)
|
||||
aDstContainer->Add( new CPOLYGON4PTS2D( corners3DU[0],
|
||||
corners3DU[3],
|
||||
corners3DU[2],
|
||||
corners3DU[1],
|
||||
*aPad ) );
|
||||
|
||||
// Add the PAD contours
|
||||
// Round segments cannot have 0-length elements, so we approximate them
|
||||
// as a small circle
|
||||
for( int i = 1; i <= 4; i++ )
|
||||
{
|
||||
if( Is_segment_a_circle( corners3DU[i - 1], corners3DU[i & 3] ) )
|
||||
case SH_CIRCLE:
|
||||
{
|
||||
aDstContainer->Add( new CFILLEDCIRCLE2D( corners3DU[i - 1],
|
||||
rounding_radius * m_biuTo3Dunits,
|
||||
*aPad ) );
|
||||
const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shape.get();
|
||||
const int radius = circle->GetRadius() + aClearanceValue.x;
|
||||
const SFVEC2F center( circle->GetCenter().x * m_biuTo3Dunits,
|
||||
-circle->GetCenter().y * m_biuTo3Dunits );
|
||||
|
||||
aDstContainer->Add( new CFILLEDCIRCLE2D( center, radius * m_biuTo3Dunits, *aPad ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aDstContainer->Add( new CROUNDSEGMENT2D( corners3DU[i - 1],
|
||||
corners3DU[i & 3],
|
||||
rounding_radius * 2.0f * m_biuTo3Dunits,
|
||||
*aPad ) );
|
||||
break;
|
||||
|
||||
case SH_SIMPLE:
|
||||
poly.AddOutline( static_cast<SHAPE_SIMPLE*>( shape.get() )->Vertices() );
|
||||
break;
|
||||
|
||||
case SH_POLY_SET:
|
||||
poly = *(SHAPE_POLY_SET*) shape.get();
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "BOARD_ADAPTER::createNewPadWithClearance unimplemented shape" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
if( !poly.IsEmpty() )
|
||||
{
|
||||
wxSize shapesize( aPad->GetSize() );
|
||||
shapesize.x += aClearanceValue.x * 2;
|
||||
shapesize.y += aClearanceValue.y * 2;
|
||||
|
||||
SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
|
||||
|
||||
int corner_radius = aPad->GetRoundRectCornerRadius( shapesize );
|
||||
TransformRoundChamferedRectToPolygon( polyList, PadShapePos, shapesize, aPad->GetOrientation(),
|
||||
corner_radius, aPad->GetChamferRectRatio(),
|
||||
aPad->GetChamferPositions(), ARC_HIGH_DEF );
|
||||
|
||||
// Add the PAD polygon
|
||||
Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits, *aPad );
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
|
||||
polyList.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
aPad->CustomShapeAsPolygonToBoardPosition( &polyList, aPad->ShapePos(), aPad->GetOrientation() );
|
||||
|
||||
if( aClearanceValue.x )
|
||||
polyList.Inflate( aClearanceValue.x, 32 );
|
||||
poly.Inflate( aClearanceValue.x, 32 );
|
||||
|
||||
// Add the PAD polygon
|
||||
Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits, *aPad );
|
||||
|
||||
}
|
||||
break;
|
||||
Convert_shape_line_polygon_to_triangles( poly, *aDstContainer, m_biuTo3Dunits, *aPad );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Based on:
|
||||
// BuildPadDrillShapePolygon
|
||||
// board_items_to_polygon_shape_transform.cpp
|
||||
COBJECT2D *BOARD_ADAPTER::createNewPadDrill( const D_PAD* aPad, int aInflateValue )
|
||||
{
|
||||
wxSize drillSize = aPad->GetDrillSize();
|
||||
|
@ -587,29 +416,16 @@ COBJECT2D *BOARD_ADAPTER::createNewPadDrill( const D_PAD* aPad, int aInflateValu
|
|||
}
|
||||
else // Oblong hole
|
||||
{
|
||||
wxPoint start, end;
|
||||
int width;
|
||||
const std::shared_ptr<SHAPE_SEGMENT>& seg = aPad->GetEffectiveHoleShape();
|
||||
float width = seg->GetWidth() + aInflateValue * 2;
|
||||
|
||||
aPad->GetOblongGeometry( aPad->GetDrillSize(), &start, &end, &width );
|
||||
SFVEC2F start3DU( seg->GetSeg().A.x * m_biuTo3Dunits,
|
||||
-seg->GetSeg().A.y * m_biuTo3Dunits );
|
||||
|
||||
width += aInflateValue * 2;
|
||||
start += aPad->GetPosition();
|
||||
end += aPad->GetPosition();
|
||||
SFVEC2F end3DU ( seg->GetSeg().B.x * m_biuTo3Dunits,
|
||||
-seg->GetSeg().B.y * m_biuTo3Dunits );
|
||||
|
||||
SFVEC2F start3DU( start.x * m_biuTo3Dunits,
|
||||
-start.y * m_biuTo3Dunits );
|
||||
|
||||
SFVEC2F end3DU ( end.x * m_biuTo3Dunits,
|
||||
-end.y * m_biuTo3Dunits );
|
||||
|
||||
if( Is_segment_a_circle( start3DU, end3DU ) )
|
||||
{
|
||||
return new CFILLEDCIRCLE2D( start3DU, (width / 2) * m_biuTo3Dunits, *aPad );
|
||||
}
|
||||
else
|
||||
{
|
||||
return new CROUNDSEGMENT2D( start3DU, end3DU, width * m_biuTo3Dunits, *aPad );
|
||||
}
|
||||
return new CROUNDSEGMENT2D( start3DU, end3DU, width * m_biuTo3Dunits, *aPad );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -951,15 +767,13 @@ void BOARD_ADAPTER::AddSolidAreasShapesToContainer( const ZONE_CONTAINER* aZoneC
|
|||
float radius = line_thickness/2;
|
||||
|
||||
if( radius > 0.0 ) // degenerated circles crash 3D viewer
|
||||
aDstContainer->Add(
|
||||
new CFILLEDCIRCLE2D( start3DU, radius,
|
||||
*aZoneContainer ) );
|
||||
aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius,
|
||||
*aZoneContainer ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aDstContainer->Add(
|
||||
new CROUNDSEGMENT2D( start3DU, end3DU, line_thickness,
|
||||
*aZoneContainer ) );
|
||||
aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, line_thickness,
|
||||
*aZoneContainer ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -986,12 +800,9 @@ void BOARD_ADAPTER::buildPadShapeThickOutlineAsSegments( const D_PAD* aPad,
|
|||
return;
|
||||
}
|
||||
|
||||
// For other shapes, draw polygon outlines
|
||||
// For other shapes, add outlines as thick segments in polygon buffer
|
||||
SHAPE_POLY_SET corners;
|
||||
aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ) );
|
||||
|
||||
|
||||
// Add outlines as thick segments in polygon buffer
|
||||
aPad->TransformShapeWithClearanceToPolygon( corners, 0 );
|
||||
|
||||
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
|
||||
|
||||
|
@ -1005,13 +816,13 @@ void BOARD_ADAPTER::buildPadShapeThickOutlineAsSegments( const D_PAD* aPad,
|
|||
|
||||
if( Is_segment_a_circle( start3DU, end3DU ) )
|
||||
{
|
||||
aDstContainer->Add(
|
||||
new CFILLEDCIRCLE2D( start3DU, ( aWidth / 2 ) * m_biuTo3Dunits, *aPad ) );
|
||||
aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, ( aWidth / 2 ) * m_biuTo3Dunits,
|
||||
*aPad ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aDstContainer->Add(
|
||||
new CROUNDSEGMENT2D( start3DU, end3DU, aWidth * m_biuTo3Dunits, *aPad ) );
|
||||
aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, aWidth * m_biuTo3Dunits,
|
||||
*aPad ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,13 +33,7 @@
|
|||
#include "board_adapter.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/cring2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/cfilledcircle2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/croundsegment2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/cpolygon4pts2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/cpolygon2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes2D/ctriangle2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/accelerators/ccontainer2d.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes3D/ccylinder.h"
|
||||
#include "../3d_rendering/3d_render_raytracing/shapes3D/clayeritem.h"
|
||||
|
||||
#include <class_board.h>
|
||||
#include <class_module.h>
|
||||
|
@ -47,16 +41,17 @@
|
|||
#include <class_pcb_text.h>
|
||||
#include <class_edge_mod.h>
|
||||
#include <class_zone.h>
|
||||
#include <class_text_mod.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <trigo.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
|
||||
#ifdef PRINT_STATISTICS_3D_VIEWER
|
||||
#include <profile.h>
|
||||
#endif
|
||||
|
||||
|
||||
void BOARD_ADAPTER::destroyLayers()
|
||||
{
|
||||
|
@ -501,13 +496,13 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
|||
|
||||
if( pad->GetAttribute () != PAD_ATTRIB_HOLE_NOT_PLATED )
|
||||
{
|
||||
pad->BuildPadDrillShapePolygon( m_through_outer_holes_poly, inflate );
|
||||
pad->BuildPadDrillShapePolygon( m_through_inner_holes_poly, 0 );
|
||||
pad->TransformHoleWithClearanceToPolygon( m_through_outer_holes_poly, inflate );
|
||||
pad->TransformHoleWithClearanceToPolygon( m_through_inner_holes_poly, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not plated, no copper.
|
||||
pad->BuildPadDrillShapePolygon( m_through_outer_holes_poly_NPTH, inflate );
|
||||
pad->TransformHoleWithClearanceToPolygon( m_through_outer_holes_poly_NPTH, inflate );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -568,11 +563,10 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
|||
|
||||
// Note: NPTH pads are not drawn on copper layers when the pad
|
||||
// has same shape as its hole
|
||||
transformPadsShapesWithClearanceToPolygon( module->Pads(),
|
||||
curr_layer_id,
|
||||
*layerPoly,
|
||||
0,
|
||||
true );
|
||||
module->TransformPadsShapesWithClearanceToPolygon( curr_layer_id,
|
||||
*layerPoly,
|
||||
0,
|
||||
true );
|
||||
|
||||
// Micro-wave modules may have items on copper layers
|
||||
module->TransformGraphicTextWithClearanceToPolygonSet( curr_layer_id,
|
||||
|
@ -983,8 +977,8 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
|||
}
|
||||
else
|
||||
{
|
||||
transformPadsShapesWithClearanceToPolygon(
|
||||
module->Pads(), curr_layer_id, *layerPoly, 0, false );
|
||||
module->TransformPadsShapesWithClearanceToPolygon( curr_layer_id, *layerPoly, 0,
|
||||
false );
|
||||
}
|
||||
|
||||
// On tech layers, use a poor circle approximation, only for texts (stroke font)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -25,9 +25,7 @@
|
|||
/**
|
||||
* @file create_layer_poly.cpp
|
||||
* @brief This file implements the creation of the pcb board items in the poly
|
||||
* contours format. It is based on the function found in the files:
|
||||
* board_items_to_polygon_shape_transform.cpp
|
||||
* board_items_to_polygon_shape_transform.cpp
|
||||
* contours format.
|
||||
*/
|
||||
|
||||
#include "board_adapter.h"
|
||||
|
@ -36,93 +34,20 @@
|
|||
#include <class_module.h>
|
||||
|
||||
|
||||
// This is the same function as in board_items_to_polygon_shape_transform.cpp
|
||||
// but it adds the rect/trapezoid shapes with a different winding
|
||||
void BOARD_ADAPTER::buildPadShapePolygon( const D_PAD* aPad,
|
||||
SHAPE_POLY_SET& aCornerBuffer,
|
||||
wxSize aInflateValue ) const
|
||||
{
|
||||
wxPoint PadShapePos = aPad->ShapePos(); /* Note: for pad having a shape offset,
|
||||
* the pad position is NOT the shape position */
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
case PAD_SHAPE_OVAL:
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
{
|
||||
// We are using TransformShapeWithClearanceToPolygon to build the shape.
|
||||
// Currently, this method uses only the same inflate value for X and Y dirs.
|
||||
// so because here this is not the case, we use a inflated dummy pad to build
|
||||
// the polygonal shape
|
||||
// TODO: remove this dummy pad when TransformShapeWithClearanceToPolygon will use
|
||||
// a wxSize to inflate the pad size
|
||||
D_PAD dummy( *aPad );
|
||||
wxSize new_size = aPad->GetSize() + aInflateValue + aInflateValue;
|
||||
dummy.SetSize( new_size );
|
||||
dummy.TransformShapeWithClearanceToPolygon( aCornerBuffer, 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_RECT:
|
||||
{
|
||||
wxPoint corners[4];
|
||||
SHAPE_LINE_CHAIN aLineChain;
|
||||
|
||||
aPad->BuildPadPolygon( corners, aInflateValue, aPad->GetOrientation() );
|
||||
|
||||
for( int ii = 0; ii < 4; ++ii )
|
||||
{
|
||||
corners[3-ii] += PadShapePos; // Shift origin to position
|
||||
aLineChain.Append( corners[3-ii].x, corners[3-ii].y );
|
||||
}
|
||||
|
||||
aLineChain.SetClosed( true );
|
||||
|
||||
aCornerBuffer.AddOutline( aLineChain );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
|
||||
auto inflate_val = std::max( aInflateValue.x, aInflateValue.y );
|
||||
|
||||
polyList.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
aPad->CustomShapeAsPolygonToBoardPosition( &polyList, aPad->ShapePos(), aPad->GetOrientation() );
|
||||
|
||||
if( inflate_val > 0 )
|
||||
{
|
||||
int numSegs = GetNrSegmentsCircle( inflate_val );
|
||||
polyList.Inflate( inflate_val, numSegs );
|
||||
}
|
||||
|
||||
aCornerBuffer.Append( polyList );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
||||
SHAPE_POLY_SET& aCornerBuffer,
|
||||
int aWidth ) const
|
||||
int aWidth ) const
|
||||
{
|
||||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
|
||||
{
|
||||
TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(),
|
||||
aPad->GetSize().x / 2, ARC_HIGH_DEF, aWidth );
|
||||
TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(), aPad->GetSize().x / 2,
|
||||
ARC_HIGH_DEF, aWidth );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// For other shapes, draw polygon outlines
|
||||
// For other shapes, add outlines as thick segments in polygon buffer
|
||||
SHAPE_POLY_SET corners;
|
||||
|
||||
buildPadShapePolygon( aPad, corners, wxSize( 0, 0 ) );
|
||||
|
||||
// Add outlines as thick segments in polygon buffer
|
||||
aPad->TransformShapeWithClearanceToPolygon( corners, 0 );
|
||||
|
||||
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
|
||||
|
||||
|
@ -131,94 +56,24 @@ void BOARD_ADAPTER::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
|||
const VECTOR2I& a = path.CPoint( ii );
|
||||
const VECTOR2I& b = path.CPoint( ii + 1 );
|
||||
|
||||
TransformSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ),
|
||||
wxPoint( b.x, b.y ), ARC_HIGH_DEF, aWidth );
|
||||
TransformSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ), wxPoint( b.x, b.y ),
|
||||
ARC_HIGH_DEF, aWidth );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Based on the same function name in board_items_to_polyshape_transform.cpp
|
||||
// It was implemented here to allow dynamic segments count per pad shape
|
||||
void BOARD_ADAPTER::transformPadsShapesWithClearanceToPolygon( const PADS& aPads, PCB_LAYER_ID aLayer,
|
||||
SHAPE_POLY_SET& aCornerBuffer,
|
||||
int aInflateValue,
|
||||
bool aSkipNPTHPadsWihNoCopper ) const
|
||||
{
|
||||
wxSize margin;
|
||||
for( auto pad : aPads )
|
||||
{
|
||||
if( !pad->IsOnLayer(aLayer) )
|
||||
continue;
|
||||
|
||||
// NPTH pads are not drawn on layers if the shape size and pos is the same
|
||||
// as their hole:
|
||||
if( aSkipNPTHPadsWihNoCopper && (pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED) )
|
||||
{
|
||||
if( (pad->GetDrillSize() == pad->GetSize()) &&
|
||||
(pad->GetOffset() == wxPoint( 0, 0 )) )
|
||||
{
|
||||
switch( pad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
|
||||
continue;
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_OVAL:
|
||||
if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
|
||||
continue;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch( aLayer )
|
||||
{
|
||||
case F_Mask:
|
||||
case B_Mask:
|
||||
margin.x = margin.y = pad->GetSolderMaskMargin() + aInflateValue;
|
||||
break;
|
||||
|
||||
case F_Paste:
|
||||
case B_Paste:
|
||||
margin = pad->GetSolderPasteMargin();
|
||||
margin.x += aInflateValue;
|
||||
margin.y += aInflateValue;
|
||||
break;
|
||||
|
||||
default:
|
||||
margin.x = margin.y = aInflateValue;
|
||||
break;
|
||||
}
|
||||
|
||||
buildPadShapePolygon( pad, aCornerBuffer, margin );
|
||||
}
|
||||
}
|
||||
|
||||
void BOARD_ADAPTER::transformGraphicModuleEdgeToPolygonSet( const MODULE *aModule,
|
||||
PCB_LAYER_ID aLayer,
|
||||
SHAPE_POLY_SET& aCornerBuffer ) const
|
||||
{
|
||||
for( auto item : aModule->GraphicalItems() )
|
||||
for( BOARD_ITEM* item : aModule->GraphicalItems() )
|
||||
{
|
||||
switch( item->Type() )
|
||||
if( item->Type() == PCB_MODULE_EDGE_T )
|
||||
{
|
||||
case PCB_MODULE_EDGE_T:
|
||||
{
|
||||
EDGE_MODULE*outline = (EDGE_MODULE*) item;
|
||||
EDGE_MODULE* outline = (EDGE_MODULE*) item;
|
||||
|
||||
if( outline->GetLayer() != aLayer )
|
||||
break;
|
||||
|
||||
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
if( outline->GetLayer() == aLayer )
|
||||
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -817,10 +817,10 @@ void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads()
|
|||
double correctionFactor = m_boardAdapter.GetCircleCorrectionFactor( nrSegments );
|
||||
int correction = radius * ( correctionFactor - 1 );
|
||||
|
||||
pad->BuildPadDrillShapePolygon(
|
||||
tht_outer_holes_poly, copperThickness + correction );
|
||||
pad->TransformHoleWithClearanceToPolygon( tht_outer_holes_poly,
|
||||
copperThickness + correction );
|
||||
|
||||
pad->BuildPadDrillShapePolygon( tht_inner_holes_poly, correction );
|
||||
pad->TransformHoleWithClearanceToPolygon( tht_inner_holes_poly, correction );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,8 +110,8 @@ void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius, const wxPoint&
|
|||
* 4 = BOTTOM_LEFT
|
||||
* 8 = BOTTOM_RIGHT
|
||||
* One can have more than one chamfered corner by ORing the corner identifers
|
||||
* @param aApproxErrorMax = the IU allowed for error in approximation
|
||||
* @param aMinSegPerCircleCount = the minimal segments per circle count in approximation
|
||||
* @param aError = the IU allowed for error in approximation
|
||||
* @param aSegsPerCircle = the minimal segments per circle count in approximation
|
||||
* (aApproxErrorMax can generate must more seg count than aMinSegPerCircleCount)
|
||||
* To allow a reasonable good shape even for very small shapes, the min count is 16
|
||||
* (must be a multiple of 4 becauseusually arcs are 90 deg.
|
||||
|
@ -119,8 +119,7 @@ void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius, const wxPoint&
|
|||
void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||
const wxPoint& aPosition, const wxSize& aSize,
|
||||
double aRotation, int aCornerRadius,
|
||||
double aChamferRatio, int aChamferCorners,
|
||||
int aApproxErrorMax, int aMinSegPerCircleCount = 16 );
|
||||
double aChamferRatio, int aChamferCorners, int aError );
|
||||
|
||||
/**
|
||||
* Function TransformRoundedEndsSegmentToPolygon
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -38,8 +38,7 @@
|
|||
#include <trigo.h>
|
||||
|
||||
|
||||
void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aBuffer,
|
||||
wxPoint aCenter, int aRadius,
|
||||
void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aCornerBuffer, wxPoint aCenter, int aRadius,
|
||||
int aError )
|
||||
{
|
||||
wxPoint corner_position;
|
||||
|
@ -56,10 +55,10 @@ void TransformCircleToPolygon( SHAPE_LINE_CHAIN& aBuffer,
|
|||
double angle = (ii * delta) + halfstep;
|
||||
RotatePoint( &corner_position, angle );
|
||||
corner_position += aCenter;
|
||||
aBuffer.Append( corner_position.x, corner_position.y );
|
||||
aCornerBuffer.Append( corner_position.x, corner_position.y );
|
||||
}
|
||||
|
||||
aBuffer.SetClosed( true );
|
||||
aCornerBuffer.SetClosed( true );
|
||||
}
|
||||
|
||||
|
||||
|
@ -192,8 +191,8 @@ void TransformOvalToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPo
|
|||
}
|
||||
|
||||
|
||||
void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius,
|
||||
const wxPoint& aPosition, const wxSize& aSize, double aRotation )
|
||||
void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius, const wxPoint& aPosition,
|
||||
const wxSize& aSize, double aRotation )
|
||||
{
|
||||
wxSize size( aSize/2 );
|
||||
|
||||
|
@ -202,25 +201,16 @@ void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius,
|
|||
|
||||
// Ensure size is > 0, to avoid generating unusable shapes
|
||||
// which can crash kicad.
|
||||
if( size.x <= 1 )
|
||||
size.x = 1;
|
||||
if( size.y <= 1 )
|
||||
size.y = 1;
|
||||
size.x = std::max( 1, size.x );
|
||||
size.y = std::max( 1, size.y );
|
||||
|
||||
aCenters[0].x = -size.x;
|
||||
aCenters[0].y = size.y;
|
||||
|
||||
aCenters[1].x = size.x;
|
||||
aCenters[1].y = size.y;
|
||||
|
||||
aCenters[2].x = size.x;
|
||||
aCenters[2].y = -size.y;
|
||||
|
||||
aCenters[3].x = -size.x;
|
||||
aCenters[3].y = -size.y;
|
||||
aCenters[0] = wxPoint( -size.x, size.y );
|
||||
aCenters[1] = wxPoint( size.x, size.y );
|
||||
aCenters[2] = wxPoint( size.x, -size.y );
|
||||
aCenters[3] = wxPoint( -size.x, -size.y );
|
||||
|
||||
// Rotate the polygon
|
||||
if( aRotation )
|
||||
if( aRotation != 0.0 )
|
||||
{
|
||||
for( int ii = 0; ii < 4; ii++ )
|
||||
RotatePoint( &aCenters[ii], aRotation );
|
||||
|
@ -232,11 +222,10 @@ void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius,
|
|||
}
|
||||
|
||||
|
||||
void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||
const wxPoint& aPosition, const wxSize& aSize,
|
||||
double aRotation, int aCornerRadius,
|
||||
double aChamferRatio, int aChamferCorners,
|
||||
int aApproxErrorMax, int aMinSegPerCircleCount )
|
||||
void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer, const wxPoint& aPosition,
|
||||
const wxSize& aSize, double aRotation,
|
||||
int aCornerRadius, double aChamferRatio,
|
||||
int aChamferCorners, int aError )
|
||||
{
|
||||
// Build the basic shape in orientation 0.0, position 0,0 for chamfered corners
|
||||
// or in actual position/orientation for round rect only
|
||||
|
@ -248,11 +237,12 @@ void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
SHAPE_POLY_SET outline;
|
||||
outline.NewOutline();
|
||||
|
||||
for( int ii = 0; ii < 4; ++ii )
|
||||
outline.Append( corners[ii].x, corners[ii].y );
|
||||
for( const wxPoint& corner : corners)
|
||||
outline.Append( corner );
|
||||
|
||||
int numSegs = std::max( GetArcToSegmentCount( aCornerRadius, aApproxErrorMax, 360.0 ),
|
||||
aMinSegPerCircleCount );
|
||||
// These are small radius corners (of which there may be many), so peg the segs-per-circle
|
||||
// to no more than 16.
|
||||
int numSegs = std::max( GetArcToSegmentCount( aCornerRadius, aError, 360.0 ), 16 );
|
||||
outline.Inflate( aCornerRadius, numSegs );
|
||||
|
||||
if( aChamferCorners == RECT_NO_CHAMFER ) // no chamfer
|
||||
|
@ -322,8 +312,7 @@ void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
}
|
||||
|
||||
|
||||
void TransformSegmentToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||
wxPoint aStart, wxPoint aEnd,
|
||||
void TransformSegmentToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoint aEnd,
|
||||
int aError, int aWidth )
|
||||
{
|
||||
int radius = aWidth / 2;
|
||||
|
@ -392,9 +381,8 @@ void TransformSegmentToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
}
|
||||
|
||||
|
||||
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||
wxPoint aCentre, wxPoint aStart, double aArcAngle,
|
||||
int aError, int aWidth )
|
||||
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCentre, wxPoint aStart,
|
||||
double aArcAngle, int aError, int aWidth )
|
||||
{
|
||||
wxPoint arc_start, arc_end;
|
||||
int dist = EuclideanNorm( aCentre - aStart );
|
||||
|
@ -404,9 +392,7 @@ void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
arc_end = arc_start = aStart;
|
||||
|
||||
if( aArcAngle != 3600 )
|
||||
{
|
||||
RotatePoint( &arc_end, aCentre, -aArcAngle );
|
||||
}
|
||||
|
||||
if( aArcAngle < 0 )
|
||||
{
|
||||
|
@ -422,8 +408,7 @@ void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
{
|
||||
curr_end = arc_start;
|
||||
RotatePoint( &curr_end, aCentre, -ii );
|
||||
TransformSegmentToPolygon( aCornerBuffer, curr_start, curr_end, aError,
|
||||
aWidth );
|
||||
TransformSegmentToPolygon( aCornerBuffer, curr_start, curr_end, aError, aWidth );
|
||||
curr_start = curr_end;
|
||||
}
|
||||
|
||||
|
@ -432,14 +417,12 @@ void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
}
|
||||
|
||||
|
||||
void TransformRingToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||
wxPoint aCentre, int aRadius,
|
||||
void TransformRingToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCentre, int aRadius,
|
||||
int aError, int aWidth )
|
||||
{
|
||||
// Compute the corners positions and creates the poly
|
||||
wxPoint curr_point;
|
||||
int inner_radius = aRadius - ( aWidth / 2 );
|
||||
int outer_radius = inner_radius + aWidth;
|
||||
int inner_radius = aRadius - ( aWidth / 2 );
|
||||
int outer_radius = inner_radius + aWidth;
|
||||
|
||||
if( inner_radius <= 0 )
|
||||
{ //In this case, the ring is just a circle (no hole inside)
|
||||
|
|
|
@ -40,8 +40,10 @@
|
|||
#include <class_edge_mod.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <math/util.h> // for KiROUND
|
||||
|
||||
|
||||
// A helper struct for the callback function
|
||||
// These variables are parameters used in addTextSegmToPoly.
|
||||
// But addTextSegmToPoly is a call-back function,
|
||||
|
@ -519,8 +521,8 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
// Most of time pads are using the segment count given by aError value.
|
||||
const int pad_min_seg_per_circle_count = 16;
|
||||
double angle = m_Orient;
|
||||
int dx = (m_Size.x / 2) + aClearanceValue;
|
||||
int dy = (m_Size.y / 2) + aClearanceValue;
|
||||
int dx = m_Size.x / 2;
|
||||
int dy = m_Size.y / 2;
|
||||
|
||||
wxPoint padShapePos = ShapePos(); // Note: for pad having a shape offset,
|
||||
// the pad position is NOT the shape position
|
||||
|
@ -528,35 +530,20 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
switch( GetShape() )
|
||||
{
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
TransformCircleToPolygon( aCornerBuffer, padShapePos, dx, aError );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_OVAL:
|
||||
|
||||
// If the oval is actually a circle (same x/y size), treat it the same
|
||||
if( dx == dy )
|
||||
{
|
||||
TransformCircleToPolygon( aCornerBuffer, padShapePos, dx, aError );
|
||||
TransformCircleToPolygon( aCornerBuffer, padShapePos, dx + aClearanceValue, aError );
|
||||
}
|
||||
else
|
||||
{
|
||||
int width;
|
||||
wxPoint shape_offset;
|
||||
if( dy > dx ) // Oval pad X/Y ratio for choosing translation axis
|
||||
{
|
||||
shape_offset.y = dy - dx;
|
||||
width = dx * 2;
|
||||
}
|
||||
else //if( dy <= dx )
|
||||
{
|
||||
shape_offset.x = dy - dx;
|
||||
width = dy * 2;
|
||||
}
|
||||
int half_width = std::min( dx, dy );
|
||||
wxPoint delta( dx - half_width, dy - half_width );
|
||||
|
||||
RotatePoint( &shape_offset, angle );
|
||||
wxPoint start = padShapePos - shape_offset;
|
||||
wxPoint end = padShapePos + shape_offset;
|
||||
TransformOvalToPolygon( aCornerBuffer, start, end, width, aError );
|
||||
RotatePoint( &delta, angle );
|
||||
|
||||
TransformOvalToPolygon( aCornerBuffer, padShapePos - delta, padShapePos + delta,
|
||||
half_width * 2 + aClearanceValue, aError );
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -564,14 +551,21 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_RECT:
|
||||
{
|
||||
int ddx = GetShape() == PAD_SHAPE_TRAPEZOID ? m_DeltaSize.x / 2 : 0;
|
||||
int ddy = GetShape() == PAD_SHAPE_TRAPEZOID ? m_DeltaSize.y / 2 : 0;
|
||||
|
||||
wxPoint corners[4];
|
||||
BuildPadPolygon( corners, wxSize( 0, 0 ), angle );
|
||||
corners[0] = wxPoint( -dx + ddy, dy + ddx );
|
||||
corners[1] = wxPoint( dx - ddy, dy - ddx );
|
||||
corners[2] = wxPoint( dx + ddy, -dy + ddx );
|
||||
corners[3] = wxPoint( -dx - ddy, -dy - ddx );
|
||||
|
||||
SHAPE_POLY_SET outline;
|
||||
outline.NewOutline();
|
||||
|
||||
for( wxPoint& corner : corners )
|
||||
{
|
||||
RotatePoint( &corner, angle );
|
||||
corner += padShapePos;
|
||||
outline.Append( corner.x, corner.y );
|
||||
}
|
||||
|
@ -615,9 +609,11 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
|
||||
outline.Append( m_customShapeAsPolygon );
|
||||
CustomShapeAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() );
|
||||
SHAPE_POLY_SET outline;
|
||||
MergePrimitivesAsPolygon( &outline );
|
||||
outline.Rotate( -DECIDEG2RAD( m_Orient ) );
|
||||
outline.Move( VECTOR2I( m_Pos ) );
|
||||
|
||||
// TODO: do we need the Simplify() & Fracture() if we're not inflating?
|
||||
outline.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
|
@ -640,91 +636,18 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
|
||||
|
||||
|
||||
/*
|
||||
* Function BuildPadShapePolygon
|
||||
* Build the corner list of the polygonal shape, depending on shape, clearance and orientation
|
||||
* Note: for round & oval pads this function is equivalent to TransformShapeWithClearanceToPolygon,
|
||||
* but not for other shapes
|
||||
*/
|
||||
void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer, wxSize aInflateValue,
|
||||
int aError ) const
|
||||
{
|
||||
switch( GetShape() )
|
||||
{
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
case PAD_SHAPE_OVAL:
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
{
|
||||
// We are using TransformShapeWithClearanceToPolygon to build the shape.
|
||||
// Currently, this method uses only the same inflate value for X and Y dirs.
|
||||
// so because here this is not the case, we use a inflated dummy pad to build
|
||||
// the polygonal shape
|
||||
// TODO: remove this dummy pad when TransformShapeWithClearanceToPolygon will use
|
||||
// a wxSize to inflate the pad size
|
||||
D_PAD dummy( *this );
|
||||
dummy.SetSize( GetSize() + aInflateValue + aInflateValue );
|
||||
dummy.TransformShapeWithClearanceToPolygon( aCornerBuffer, 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_RECT:
|
||||
{
|
||||
wxPoint corners[4];
|
||||
wxPoint padShapePos = ShapePos(); // Note: for pad having a shape offset,
|
||||
// the pad position is NOT the shape position
|
||||
|
||||
aCornerBuffer.NewOutline();
|
||||
BuildPadPolygon( corners, aInflateValue, m_Orient );
|
||||
|
||||
for( wxPoint& corner : corners )
|
||||
{
|
||||
corner += padShapePos; // Shift origin to position
|
||||
aCornerBuffer.Append( corner.x, corner.y );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
// For a custom shape, that is in fact a polygon (with holes), we use only a single
|
||||
// inflate value (different values for X and Y have no definition for a custom pad).
|
||||
int inflate = ( aInflateValue.x + aInflateValue.y ) / 2;
|
||||
|
||||
TransformShapeWithClearanceToPolygon( aCornerBuffer, inflate );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool D_PAD::BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer, int aInflateValue,
|
||||
int aError ) const
|
||||
bool D_PAD::TransformHoleWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aInflateValue,
|
||||
int aError ) const
|
||||
{
|
||||
wxSize drillsize = GetDrillSize();
|
||||
|
||||
if( !drillsize.x || !drillsize.y )
|
||||
return false;
|
||||
|
||||
if( drillsize.x == drillsize.y ) // usual round hole
|
||||
{
|
||||
int radius = ( drillsize.x / 2 ) + aInflateValue;
|
||||
TransformCircleToPolygon( aCornerBuffer, GetPosition(), radius, aError );
|
||||
}
|
||||
else // Oblong hole
|
||||
{
|
||||
wxPoint start, end;
|
||||
int width;
|
||||
const std::shared_ptr<SHAPE_SEGMENT>& seg = GetEffectiveHoleShape();
|
||||
|
||||
GetOblongGeometry( GetDrillSize(), &start, &end, &width );
|
||||
|
||||
start += GetPosition();
|
||||
end += GetPosition();
|
||||
width += aInflateValue * 2;
|
||||
|
||||
TransformSegmentToPolygon( aCornerBuffer, start, end, aError, width );
|
||||
}
|
||||
TransformSegmentToPolygon( aCornerBuffer, (wxPoint) seg->GetSeg().A, (wxPoint) seg->GetSeg().B,
|
||||
aError, seg->GetWidth() + aInflateValue * 2 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -243,15 +243,8 @@ public:
|
|||
double GetLocalSolderPasteMarginRatio() const { return m_LocalSolderPasteMarginRatio; }
|
||||
void SetLocalSolderPasteMarginRatio( double aRatio ) { m_LocalSolderPasteMarginRatio = aRatio; }
|
||||
|
||||
void SetZoneConnection( ZONE_CONNECTION aType )
|
||||
{
|
||||
m_ZoneConnection = aType;
|
||||
}
|
||||
|
||||
ZONE_CONNECTION GetZoneConnection() const
|
||||
{
|
||||
return m_ZoneConnection;
|
||||
}
|
||||
void SetZoneConnection( ZONE_CONNECTION aType ) { m_ZoneConnection = aType; }
|
||||
ZONE_CONNECTION GetZoneConnection() const { return m_ZoneConnection; }
|
||||
|
||||
void SetThermalWidth( int aWidth ) { m_ThermalWidth = aWidth; }
|
||||
int GetThermalWidth() const { return m_ThermalWidth; }
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -40,6 +40,8 @@
|
|||
|
||||
class DRAWSEGMENT;
|
||||
class PARAM_CFG;
|
||||
class SHAPE;
|
||||
class SHAPE_SEGMENT;
|
||||
|
||||
enum CUST_PAD_SHAPE_IN_ZONE
|
||||
{
|
||||
|
@ -52,7 +54,6 @@ class EDA_3D_CANVAS;
|
|||
class MODULE;
|
||||
class EDGE_MODULE;
|
||||
class TRACK;
|
||||
class MSG_PANEL_INFO;
|
||||
|
||||
namespace KIGFX
|
||||
{
|
||||
|
@ -115,10 +116,6 @@ public:
|
|||
|
||||
class D_PAD : public BOARD_CONNECTED_ITEM
|
||||
{
|
||||
public:
|
||||
static int m_PadSketchModePenSize; ///< Pen size used to draw pads in sketch mode
|
||||
///< (mode used to print pads on silkscreen layer)
|
||||
|
||||
public:
|
||||
D_PAD( MODULE* parent );
|
||||
|
||||
|
@ -181,34 +178,14 @@ public:
|
|||
* Set the pad name (sometimes called pad number, although
|
||||
* it can be an array reference like AA12).
|
||||
*/
|
||||
void SetName( const wxString& aName )
|
||||
{
|
||||
m_name = aName;
|
||||
}
|
||||
void SetName( const wxString& aName ) { m_name = aName; }
|
||||
const wxString& GetName() const { return m_name; }
|
||||
|
||||
/**
|
||||
* Set the pad function (pin name in schematic)
|
||||
*/
|
||||
void SetPinFunction( const wxString& aName )
|
||||
{
|
||||
m_pinFunction = aName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the pad name
|
||||
*/
|
||||
const wxString& GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the pad function (pin name in schematic)
|
||||
*/
|
||||
const wxString& GetPinFunction() const
|
||||
{
|
||||
return m_pinFunction;
|
||||
}
|
||||
void SetPinFunction( const wxString& aName ) { m_pinFunction = aName; }
|
||||
const wxString& GetPinFunction() const { return m_pinFunction; }
|
||||
|
||||
bool PadNameEqual( const D_PAD* other ) const
|
||||
{
|
||||
|
@ -219,8 +196,8 @@ public:
|
|||
* Function GetShape
|
||||
* @return the shape of this pad.
|
||||
*/
|
||||
PAD_SHAPE_T GetShape() const { return m_padShape; }
|
||||
void SetShape( PAD_SHAPE_T aShape ) { m_padShape = aShape; m_boundingRadius = -1; }
|
||||
void SetShape( PAD_SHAPE_T aShape ) { m_padShape = aShape; m_shapesDirty = true; }
|
||||
PAD_SHAPE_T GetShape() const { return m_padShape; }
|
||||
|
||||
void SetPosition( const wxPoint& aPos ) override { m_Pos = aPos; }
|
||||
const wxPoint GetPosition() const override { return m_Pos; }
|
||||
|
@ -259,7 +236,7 @@ public:
|
|||
void SetAnchorPadShape( PAD_SHAPE_T aShape )
|
||||
{
|
||||
m_anchorPadShape = ( aShape == PAD_SHAPE_RECT ) ? PAD_SHAPE_RECT : PAD_SHAPE_CIRCLE;
|
||||
m_boundingRadius = -1;
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,8 +249,8 @@ public:
|
|||
return ( GetLayerSet() & LSET::AllCuMask() ) != 0;
|
||||
}
|
||||
|
||||
void SetY( int y ) { m_Pos.y = y; }
|
||||
void SetX( int x ) { m_Pos.x = x; }
|
||||
void SetY( int y ) { m_Pos.y = y; m_shapesDirty = true; }
|
||||
void SetX( int x ) { m_Pos.x = x; m_shapesDirty = true; }
|
||||
|
||||
void SetPos0( const wxPoint& aPos ) { m_Pos0 = aPos; }
|
||||
const wxPoint& GetPos0() const { return m_Pos0; }
|
||||
|
@ -281,16 +258,16 @@ public:
|
|||
void SetY0( int y ) { m_Pos0.y = y; }
|
||||
void SetX0( int x ) { m_Pos0.x = x; }
|
||||
|
||||
void SetSize( const wxSize& aSize ) { m_Size = aSize; m_boundingRadius = -1; }
|
||||
void SetSize( const wxSize& aSize ) { m_Size = aSize; m_shapesDirty = true; }
|
||||
const wxSize& GetSize() const { return m_Size; }
|
||||
|
||||
void SetDelta( const wxSize& aSize ) { m_DeltaSize = aSize; m_boundingRadius = -1; }
|
||||
void SetDelta( const wxSize& aSize ) { m_DeltaSize = aSize; m_shapesDirty = true; }
|
||||
const wxSize& GetDelta() const { return m_DeltaSize; }
|
||||
|
||||
void SetDrillSize( const wxSize& aSize ) { m_Drill = aSize; }
|
||||
void SetDrillSize( const wxSize& aSize ) { m_Drill = aSize; m_shapesDirty = true; }
|
||||
const wxSize& GetDrillSize() const { return m_Drill; }
|
||||
|
||||
void SetOffset( const wxPoint& aOffset ) { m_Offset = aOffset; }
|
||||
void SetOffset( const wxPoint& aOffset ) { m_Offset = aOffset; m_shapesDirty = true; }
|
||||
const wxPoint& GetOffset() const { return m_Offset; }
|
||||
|
||||
/**
|
||||
|
@ -303,67 +280,35 @@ public:
|
|||
* a arc
|
||||
* a curve
|
||||
*/
|
||||
void AddPrimitivePoly( const SHAPE_POLY_SET& aPoly, int aThickness,
|
||||
bool aMergePrimitives = true );
|
||||
void AddPrimitivePoly( const std::vector<wxPoint>& aPoly, int aThickness,
|
||||
bool aMergePrimitives = true );
|
||||
void AddPrimitiveSegment( const wxPoint& aStart, const wxPoint& aEnd, int aThickness,
|
||||
bool aMergePrimitives = true );
|
||||
void AddPrimitiveCircle( const wxPoint& aCenter, int aRadius, int aThickness,
|
||||
bool aMergePrimitives = true ); ///< ring or circle basic shape
|
||||
void AddPrimitiveRect( const wxPoint& aStart, const wxPoint& aEnd, int aThickness,
|
||||
bool aMergePrimitives = true );
|
||||
void AddPrimitivePoly( const SHAPE_POLY_SET& aPoly, int aThickness );
|
||||
void AddPrimitivePoly( const std::vector<wxPoint>& aPoly, int aThickness );
|
||||
void AddPrimitiveSegment( const wxPoint& aStart, const wxPoint& aEnd, int aThickness );
|
||||
void AddPrimitiveCircle( const wxPoint& aCenter, int aRadius, int aThickness );
|
||||
void AddPrimitiveRect( const wxPoint& aStart, const wxPoint& aEnd, int aThickness );
|
||||
void AddPrimitiveArc( const wxPoint& aCenter, const wxPoint& aStart, int aArcAngle,
|
||||
int aThickness, bool aMergePrimitives = true );
|
||||
int aThickness );
|
||||
void AddPrimitiveCurve( const wxPoint& aStart, const wxPoint& aEnd, const wxPoint& aCtrl1,
|
||||
const wxPoint& aCtrl2, int aThickness, bool aMergePrimitives = true );
|
||||
const wxPoint& aCtrl2, int aThickness );
|
||||
|
||||
|
||||
bool GetBestAnchorPosition( VECTOR2I& aPos );
|
||||
|
||||
/**
|
||||
* Merge all basic shapes, converted to a polygon in one polygon,
|
||||
* in m_customShapeAsPolygon
|
||||
* @return true if OK, false in there is more than one polygon
|
||||
* in m_customShapeAsPolygon
|
||||
* @param aMergedPolygon = the SHAPE_POLY_SET to fill.
|
||||
* if NULL, m_customShapeAsPolygon is the target
|
||||
* @param aCircleToSegmentsCount = number of segment to approximate a circle
|
||||
* (default = 32)
|
||||
* Merge all basic shapes to a SHAPE_POLY_SET
|
||||
* Note: The corners coordinates are relative to the pad position, orientation 0,
|
||||
*/
|
||||
bool MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon = NULL );
|
||||
void MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon ) const;
|
||||
|
||||
/**
|
||||
* clear the basic shapes list
|
||||
*/
|
||||
void DeletePrimitivesList();
|
||||
|
||||
/**
|
||||
* When created, the corners coordinates are relative to the pad position, orientation 0,
|
||||
* in m_customShapeAsPolygon
|
||||
* CustomShapeAsPolygonToBoardPosition transform these coordinates to actual
|
||||
* (board) coordinates
|
||||
* @param aMergedPolygon = the corners coordinates, relative to aPosition and
|
||||
* rotated by aRotation
|
||||
* @param aPosition = the position of the shape (usually the pad shape, but
|
||||
* not always, when moving the pad)
|
||||
* @param aRotation = the rotation of the shape (usually the pad rotation, but
|
||||
* not always, in DRC)
|
||||
*/
|
||||
void CustomShapeAsPolygonToBoardPosition( SHAPE_POLY_SET * aMergedPolygon,
|
||||
wxPoint aPosition, double aRotation ) const;
|
||||
|
||||
/**
|
||||
* Accessor to the basic shape list
|
||||
*/
|
||||
const std::vector<PAD_CS_PRIMITIVE>& GetPrimitives() const { return m_basicShapes; }
|
||||
|
||||
/**
|
||||
* Accessor to the custom shape as one polygon
|
||||
*/
|
||||
const SHAPE_POLY_SET& GetCustomShapeAsPolygon() const { return m_customShapeAsPolygon; }
|
||||
|
||||
void Flip( const wxPoint& aCentre, bool aFlipLeftRight ) override;
|
||||
|
||||
/**
|
||||
|
@ -373,24 +318,18 @@ public:
|
|||
|
||||
/**
|
||||
* Mirror the primitives about a coordinate
|
||||
*
|
||||
* @param aX the x coordinate about which to mirror
|
||||
*/
|
||||
void MirrorXPrimitives( int aX );
|
||||
|
||||
/**
|
||||
* Import to the basic shape list
|
||||
* @return true if OK, false if issues
|
||||
* (more than one polygon to build the polygon shape list)
|
||||
*/
|
||||
bool SetPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList );
|
||||
void SetPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList );
|
||||
|
||||
/**
|
||||
* Add to the basic shape list
|
||||
* @return true if OK, false if issues
|
||||
* (more than one polygon to build the polygon shape list)
|
||||
*/
|
||||
bool AddPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList );
|
||||
void AddPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList );
|
||||
|
||||
|
||||
/**
|
||||
|
@ -414,21 +353,11 @@ public:
|
|||
double GetOrientationDegrees() const { return m_Orient/10.0; }
|
||||
double GetOrientationRadians() const { return m_Orient*M_PI/1800; }
|
||||
|
||||
void SetDrillShape( PAD_DRILL_SHAPE_T aDrillShape )
|
||||
{ m_drillShape = aDrillShape; }
|
||||
void SetDrillShape( PAD_DRILL_SHAPE_T aShape ) { m_drillShape = aShape; m_shapesDirty = true; }
|
||||
PAD_DRILL_SHAPE_T GetDrillShape() const { return m_drillShape; }
|
||||
|
||||
/**
|
||||
* Function GetOblongGeometry calculates the start point, end point and width of an
|
||||
* equivalent segment which have the same position and width as the pad (for circular
|
||||
* of oval pads) or hole
|
||||
*
|
||||
* NB: points returned are RELATIVE to the PAD POSITION. For board coordinates holes
|
||||
* will need to be offset by GetPosition() and pads by ShapePos().
|
||||
*
|
||||
* @param aStartPoint = first point of the equivalent segment, relative to the pad position.
|
||||
* @param aEndPoint = second point of the equivalent segment, relative to the pad position.
|
||||
* @param aWidth = width equivalent segment.
|
||||
* JEY TODO: temporary until Tom is done with DRC stuff....
|
||||
*/
|
||||
void GetOblongGeometry( const wxSize& aDrillOrPadSize,
|
||||
wxPoint* aStartPoint, wxPoint* aEndPoint, int* aWidth ) const;
|
||||
|
@ -461,20 +390,47 @@ public:
|
|||
double GetLocalSolderPasteMarginRatio() const { return m_LocalSolderPasteMarginRatio; }
|
||||
void SetLocalSolderPasteMarginRatio( double aRatio ) { m_LocalSolderPasteMarginRatio = aRatio; }
|
||||
|
||||
|
||||
/**
|
||||
* Function TransformShapeWithClearanceToPolygon
|
||||
* Convert the pad shape to a closed polygon
|
||||
* Used in filling zones calculations
|
||||
* Circles and arcs are approximated by segments
|
||||
* Convert the pad shape to a closed polygon. Circles and arcs are approximated by segments.
|
||||
* @param aCornerBuffer = a buffer to store the polygon
|
||||
* @param aClearanceValue = the clearance around the pad
|
||||
* @param aMaxError = Maximum error from true when converting arcs
|
||||
* @param ignoreLineWidth = used for edge cut items where the line width is only
|
||||
* for visualization
|
||||
* @param aMaxError = maximum error from true when converting arcs
|
||||
* @param ignoreLineWidth = used for edge cuts where the line width is only for visualization
|
||||
*/
|
||||
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue,
|
||||
int aMaxError = ARC_HIGH_DEF, bool ignoreLineWidth = false ) const override;
|
||||
int aMaxError = ARC_HIGH_DEF,
|
||||
bool ignoreLineWidth = false ) const override;
|
||||
|
||||
/**
|
||||
* Function TransformHoleWithClearanceToPolygon
|
||||
* Build the Corner list of the polygonal drill shape in the board coordinate system.
|
||||
* @param aCornerBuffer = a buffer to fill.
|
||||
* @param aInflateValue = the clearance or margin value.
|
||||
* @param aError = maximum deviation of an arc from the polygon approximation
|
||||
* @return false if the pad has no hole, true otherwise
|
||||
*/
|
||||
bool TransformHoleWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aInflateValue,
|
||||
int aError = ARC_HIGH_DEF ) const;
|
||||
|
||||
/**
|
||||
* Function GetEffectiveShapes
|
||||
* Returns a list of SHAPE objects representing the pad's copper.
|
||||
*/
|
||||
const std::vector<std::shared_ptr<SHAPE>>& GetEffectiveShapes() const;
|
||||
|
||||
/**
|
||||
* Function GetEffectiveHoleShape
|
||||
* Returns a list of SHAPE objects representing the pad's hole.
|
||||
*/
|
||||
const std::shared_ptr<SHAPE_SEGMENT>& GetEffectiveHoleShape() const;
|
||||
|
||||
/**
|
||||
* Function GetBoundingRadius
|
||||
* returns the radius of a minimum sized circle which fully encloses this pad.
|
||||
* The center is the pad position NOT THE SHAPE POS!
|
||||
*/
|
||||
int GetBoundingRadius() const;
|
||||
|
||||
/**
|
||||
* Function GetLocalClearanceOverrides
|
||||
|
@ -515,17 +471,14 @@ public:
|
|||
*/
|
||||
wxSize GetSolderPasteMargin() const;
|
||||
|
||||
void SetZoneConnection( ZONE_CONNECTION aType )
|
||||
{
|
||||
m_ZoneConnection = aType;
|
||||
}
|
||||
void SetZoneConnection( ZONE_CONNECTION aType ) { m_ZoneConnection = aType; }
|
||||
ZONE_CONNECTION GetZoneConnection() const { return m_ZoneConnection; }
|
||||
|
||||
ZONE_CONNECTION GetZoneConnection() const;
|
||||
|
||||
ZONE_CONNECTION GetLocalZoneConnection() const
|
||||
{
|
||||
return m_ZoneConnection;
|
||||
}
|
||||
/**
|
||||
* Return the zone connection in effect (either locally overridden or overridden in the
|
||||
* parent module).
|
||||
*/
|
||||
ZONE_CONNECTION GetEffectiveZoneConnection() const;
|
||||
|
||||
void SetThermalWidth( int aWidth ) { m_ThermalWidth = aWidth; }
|
||||
int GetThermalWidth() const;
|
||||
|
@ -534,110 +487,12 @@ public:
|
|||
int GetThermalGap() const;
|
||||
|
||||
/**
|
||||
* Function BuildPadPolygon
|
||||
* Has meaning only for polygonal pads (trapezoid and rectangular)
|
||||
* Build the Corner list of the polygonal shape,
|
||||
* depending on shape, extra size (clearance ...) and orientation
|
||||
* @param aCoord = a buffer to fill (4 corners).
|
||||
* @param aInflateValue = wxSize: the clearance or margin value. value > 0:
|
||||
* inflate, < 0 deflate
|
||||
* @param aRotation = full rotation of the polygon
|
||||
*/
|
||||
void BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, double aRotation ) const;
|
||||
|
||||
/**
|
||||
* Function GetRoundRectCornerRadius
|
||||
* Function SetRoundRectCornerRadius
|
||||
* Has meaning only for rounded rect pads
|
||||
* @return The radius of the rounded corners for this pad.
|
||||
*/
|
||||
int GetRoundRectCornerRadius() const
|
||||
{
|
||||
return GetRoundRectCornerRadius( m_Size );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function GetRoundRectCornerRadius
|
||||
* Has meaning only for rounded rect pads
|
||||
* Returns the radius of the rounded corners of a rectangle
|
||||
* size aSize, using others setting of the pad
|
||||
* @param aSize = size of the of the round rect. Usually the pad size
|
||||
* but can be the size of the pad on solder mask or solder paste
|
||||
* @return The radius of the rounded corners for this pad size.
|
||||
*/
|
||||
int GetRoundRectCornerRadius( const wxSize& aSize ) const;
|
||||
|
||||
/**
|
||||
* Set the rounded rectangle radius ratio based on a given radius
|
||||
* @param aRadius = desired radius of curvature
|
||||
*/
|
||||
void SetRoundRectCornerRadius( double aRadius );
|
||||
|
||||
/**
|
||||
* Function BuildPadShapePolygon
|
||||
* Build the Corner list of the polygonal shape,
|
||||
* depending on shape, extra size (clearance ...) pad and orientation
|
||||
* This function is similar to TransformShapeWithClearanceToPolygon,
|
||||
* but the difference is BuildPadShapePolygon creates a polygon shape exactly
|
||||
* similar to pad shape, which a size inflated by aInflateValue
|
||||
* and TransformShapeWithClearanceToPolygon creates a more complex shape (for instance
|
||||
* a rectangular pad is converted in a rectangulr shape with ronded corners)
|
||||
* @param aCornerBuffer = a buffer to fill.
|
||||
* @param aInflateValue = the clearance or margin value.
|
||||
* value > 0: inflate, < 0 deflate, = 0 : no change
|
||||
* the clearance can have different values for x and y directions
|
||||
* (relative to the pad)
|
||||
* @param aError = Maximum deviation of an arc from the polygon segment
|
||||
*/
|
||||
void BuildPadShapePolygon(
|
||||
SHAPE_POLY_SET& aCornerBuffer, wxSize aInflateValue, int aError = ARC_HIGH_DEF ) const;
|
||||
|
||||
/**
|
||||
* Function BuildPadDrillShapePolygon
|
||||
* Build the Corner list of the polygonal drill shape,
|
||||
* depending on shape pad hole and orientation
|
||||
* @param aCornerBuffer = a buffer to fill.
|
||||
* @param aInflateValue = the clearance or margin value.
|
||||
* value > 0: inflate, < 0 deflate, = 0 : no change
|
||||
* @param aError = Maximum deviation of an arc from the polygon approximation
|
||||
* @return false if the pad has no hole, true otherwise
|
||||
*/
|
||||
bool BuildPadDrillShapePolygon(
|
||||
SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aError = ARC_HIGH_DEF ) const;
|
||||
|
||||
/**
|
||||
* Function BuildSegmentFromOvalShape
|
||||
* Has meaning only for OVAL (and ROUND) pads
|
||||
* Build an equivalent segment having the same shape as the OVAL shape,
|
||||
* Useful in draw function and in DRC and HitTest functions,
|
||||
* because segments are already well handled by track tests
|
||||
* @param aSegStart = the starting point of the equivalent segment relative to the shape
|
||||
* position.
|
||||
* @param aSegEnd = the ending point of the equivalent segment, relative to the shape position
|
||||
* @param aRotation = full rotation of the segment
|
||||
* @param aRotation = full rotation of the segment
|
||||
* @param aMargin = a margin around the shape (for instance mask margin)
|
||||
* @return the width of the segment
|
||||
*/
|
||||
int BuildSegmentFromOvalShape( wxPoint& aSegStart, wxPoint& aSegEnd,
|
||||
double aRotation, const wxSize& aMargin ) const;
|
||||
|
||||
/**
|
||||
* Function GetBoundingRadius
|
||||
* returns the radius of a minimum sized circle which fully encloses this pad.
|
||||
* The center is the pad position
|
||||
*/
|
||||
int GetBoundingRadius() const
|
||||
{
|
||||
// Any member function which would affect this calculation should set
|
||||
// m_boundingRadius to -1 to re-trigger the calculation from here.
|
||||
// Currently that is only m_Size, m_DeltaSize, and m_padShape accessors.
|
||||
if( m_boundingRadius == -1 )
|
||||
{
|
||||
m_boundingRadius = boundingRadius();
|
||||
}
|
||||
|
||||
return m_boundingRadius;
|
||||
}
|
||||
int GetRoundRectCornerRadius() const;
|
||||
|
||||
wxPoint ShapePos() const;
|
||||
|
||||
|
@ -648,36 +503,8 @@ public:
|
|||
* Cannot be > 0.5
|
||||
* the normalized IPC-7351C value is 0.25
|
||||
*/
|
||||
double GetRoundRectRadiusRatio() const
|
||||
{
|
||||
return m_padRoundRectRadiusScale;
|
||||
}
|
||||
|
||||
/**
|
||||
* has meaning only for rounded rect pads
|
||||
* Set the scaling factor between the smaller Y or Y size and the radius
|
||||
* of the rounded corners.
|
||||
* Cannot be < 0.5 and obviously must be > 0
|
||||
* the normalized IPC-7351C value is 0.25
|
||||
*/
|
||||
void SetRoundRectRadiusRatio( double aRadiusScale )
|
||||
{
|
||||
if( aRadiusScale < 0.0 )
|
||||
aRadiusScale = 0.0;
|
||||
|
||||
m_padRoundRectRadiusScale = std::min( aRadiusScale, 0.5 );
|
||||
}
|
||||
|
||||
/**
|
||||
* has meaning only for chamfered rect pads
|
||||
* @return the ratio between the smaller Y or Y size and the radius
|
||||
* of the rounded corners.
|
||||
* Cannot be > 0.5
|
||||
*/
|
||||
double GetChamferRectRatio() const
|
||||
{
|
||||
return m_padChamferRectScale;
|
||||
}
|
||||
void SetRoundRectRadiusRatio( double aRadiusScale );
|
||||
double GetRoundRectRadiusRatio() const { return m_padRoundRectRadiusScale; }
|
||||
|
||||
/**
|
||||
* has meaning only for chamfered rect pads
|
||||
|
@ -685,19 +512,8 @@ public:
|
|||
* of the rounded corners.
|
||||
* Cannot be < 0.5 and obviously must be > 0
|
||||
*/
|
||||
void SetChamferRectRatio( double aChamferScale )
|
||||
{
|
||||
if( aChamferScale < 0.0 )
|
||||
aChamferScale = 0.0;
|
||||
|
||||
m_padChamferRectScale = std::min( aChamferScale, 0.5 );
|
||||
}
|
||||
|
||||
/**
|
||||
* has meaning only for chamfered rect pads
|
||||
* @return the position of the chamfer for a 0 orientation
|
||||
*/
|
||||
int GetChamferPositions() const { return m_chamferPositions; }
|
||||
void SetChamferRectRatio( double aChamferScale );
|
||||
double GetChamferRectRatio() const { return m_padChamferRectScale; }
|
||||
|
||||
/**
|
||||
* has meaning only for chamfered rect pads
|
||||
|
@ -705,10 +521,8 @@ public:
|
|||
* RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_TOP_RIGHT,
|
||||
* RECT_CHAMFER_BOTTOM_LEFT, RECT_CHAMFER_BOTTOM_RIGHT
|
||||
*/
|
||||
void SetChamferPositions( int aChamferPositions )
|
||||
{
|
||||
m_chamferPositions = aChamferPositions;
|
||||
}
|
||||
void SetChamferPositions( int aPositions ) { m_chamferPositions = aPositions; }
|
||||
int GetChamferPositions() const { return m_chamferPositions; }
|
||||
|
||||
/**
|
||||
* Function GetSubRatsnest
|
||||
|
@ -814,40 +628,36 @@ public:
|
|||
|
||||
private:
|
||||
/**
|
||||
* Function boundingRadius
|
||||
* Function calcBoundingRadius
|
||||
* returns a calculated radius of a bounding circle for this pad.
|
||||
*/
|
||||
int boundingRadius() const;
|
||||
int calcBoundingRadius() const;
|
||||
|
||||
bool buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError );
|
||||
void addCustomPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const;
|
||||
|
||||
private: // Private variable members:
|
||||
|
||||
// Actually computed and cached on demand by the accessor
|
||||
mutable int m_boundingRadius; ///< radius of the circle containing the pad shape
|
||||
void buildEffectiveShapes() const;
|
||||
|
||||
private:
|
||||
wxString m_name; ///< pad name (pin number in schematic)
|
||||
|
||||
wxString m_pinFunction; ///< pin function in schematic
|
||||
|
||||
// TODO: Remove m_Pos from Pad or make private. View positions calculated from m_Pos0
|
||||
wxPoint m_Pos; ///< pad Position on board
|
||||
|
||||
PAD_SHAPE_T m_padShape; ///< Shape: PAD_SHAPE_CIRCLE, PAD_SHAPE_RECT,
|
||||
///< PAD_SHAPE_OVAL, PAD_SHAPE_TRAPEZOID,
|
||||
///< PAD_SHAPE_ROUNDRECT, PAD_SHAPE_POLYGON
|
||||
|
||||
mutable bool m_shapesDirty;
|
||||
mutable int m_effectiveBoundingRadius;
|
||||
mutable std::vector<std::shared_ptr<SHAPE>> m_effectiveShapes;
|
||||
mutable std::shared_ptr<SHAPE_SEGMENT> m_effectiveHoleShape;
|
||||
|
||||
/** for free shape pads: a list of basic shapes,
|
||||
* in local coordinates, orient 0, coordinates relative to m_Pos
|
||||
* They are expected to define only one copper area.
|
||||
*/
|
||||
std::vector<PAD_CS_PRIMITIVE> m_basicShapes;
|
||||
|
||||
/** for free shape pads: the set of basic shapes, merged as one polygon,
|
||||
* in local coordinates, orient 0, coordinates relative to m_Pos
|
||||
*/
|
||||
SHAPE_POLY_SET m_customShapeAsPolygon;
|
||||
|
||||
/**
|
||||
* How to build the custom shape in zone, to create the clearance area:
|
||||
* CUST_PAD_SHAPE_IN_ZONE_OUTLINE = use pad shape
|
||||
|
@ -871,10 +681,10 @@ private: // Private variable members:
|
|||
///< to corner radius, default 0.25
|
||||
double m_padChamferRectScale; ///< scaling factor from smallest m_Size coord
|
||||
///< to chamfer value, default 0.25
|
||||
int m_chamferPositions; ///< the positions of the chamfered position for a 0 orientation
|
||||
int m_chamferPositions; ///< the positions of the chamfers for a 0 orientation
|
||||
|
||||
PAD_SHAPE_T m_anchorPadShape; ///< for custom shaped pads: shape of pad anchor,
|
||||
///< PAD_SHAPE_RECT, PAD_SHAPE_CIRCLE
|
||||
PAD_SHAPE_T m_anchorPadShape; ///< for custom shaped pads: shape of pad anchor,
|
||||
///< PAD_SHAPE_RECT, PAD_SHAPE_CIRCLE
|
||||
|
||||
/**
|
||||
* m_Offset is useful only for oblong and rect pads (it can be used for other
|
||||
|
|
|
@ -784,10 +784,10 @@ void ZONE_CONTAINER::Mirror( const wxPoint& aMirrorRef, bool aMirrorLeftRight )
|
|||
|
||||
ZONE_CONNECTION ZONE_CONTAINER::GetPadConnection( D_PAD* aPad ) const
|
||||
{
|
||||
if( aPad == NULL || aPad->GetZoneConnection() == ZONE_CONNECTION::INHERITED )
|
||||
if( aPad == NULL || aPad->GetEffectiveZoneConnection() == ZONE_CONNECTION::INHERITED )
|
||||
return m_PadConnection;
|
||||
else
|
||||
return aPad->GetZoneConnection();
|
||||
return aPad->GetEffectiveZoneConnection();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const
|
|||
RotatePoint( pt1, pad->ShapePos(), pad->GetOrientation() );
|
||||
|
||||
SHAPE_POLY_SET padPolySet;
|
||||
pad->BuildPadShapePolygon( padPolySet, wxSize( 0, 0 ), ARC_LOW_DEF );
|
||||
pad->TransformShapeWithClearanceToPolygon( padPolySet, 0, ARC_LOW_DEF );
|
||||
const SHAPE_LINE_CHAIN& padOutline = padPolySet.COutline( 0 );
|
||||
SHAPE_LINE_CHAIN::INTERSECTIONS intersections;
|
||||
|
||||
|
|
|
@ -551,7 +551,7 @@ void DIALOG_PAD_PROPERTIES::initValues()
|
|||
else
|
||||
m_SolderPasteMarginRatioCtrl->SetValue( msg );
|
||||
|
||||
switch( m_dummyPad->GetLocalZoneConnection() )
|
||||
switch( m_dummyPad->GetZoneConnection() )
|
||||
{
|
||||
default:
|
||||
case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
|
||||
|
@ -1199,7 +1199,10 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
|
|||
|
||||
if( m_dummyPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
if( !m_dummyPad->MergePrimitivesAsPolygon( ) )
|
||||
SHAPE_POLY_SET mergedPolygon;
|
||||
m_dummyPad->MergePrimitivesAsPolygon( &mergedPolygon );
|
||||
|
||||
if( mergedPolygon.OutlineCount() > 1 )
|
||||
error_msgs.Add( _( "Incorrect pad shape: the shape must be equivalent to only one polygon" ) );
|
||||
}
|
||||
|
||||
|
@ -1446,7 +1449,7 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow()
|
|||
m_currentPad->SetRoundRectRadiusRatio( m_padMaster->GetRoundRectRadiusRatio() );
|
||||
m_currentPad->SetChamferRectRatio( m_padMaster->GetChamferRectRatio() );
|
||||
m_currentPad->SetChamferPositions( m_padMaster->GetChamferPositions() );
|
||||
m_currentPad->SetZoneConnection( m_padMaster->GetZoneConnection() );
|
||||
m_currentPad->SetZoneConnection( m_padMaster->GetEffectiveZoneConnection() );
|
||||
|
||||
// rounded rect pads with radius ratio = 0 are in fact rect pads.
|
||||
// So set the right shape (and perhaps issues with a radius = 0)
|
||||
|
|
|
@ -1084,10 +1084,9 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
|
|||
|
||||
// Fast test to detect a pad candidate inside the text bounding box
|
||||
// Finer test (time consumming) is made only for pads near the text.
|
||||
int bb_radius = pad->GetBoundingRadius() + minClearance;
|
||||
VECTOR2I shape_pos( pad->ShapePos() );
|
||||
int bb_radius = pad->GetBoundingRadius() + minClearance;
|
||||
|
||||
if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) )
|
||||
if( !rect_area.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
|
||||
continue;
|
||||
|
||||
SHAPE_POLY_SET padOutline;
|
||||
|
|
|
@ -685,230 +685,37 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
|
||||
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance, int* aActual )
|
||||
{
|
||||
// relativePadPos is the aPad shape position relative to the aRefPad shape position
|
||||
wxPoint relativePadPos = aPad->ShapePos() - aRefPad->ShapePos();
|
||||
|
||||
int center2center = KiROUND( EuclideanNorm( relativePadPos ) );
|
||||
int center2center = KiROUND( EuclideanNorm( aPad->ShapePos() - aRefPad->ShapePos() ) );
|
||||
|
||||
// Quick test: Clearance is OK if the bounding circles are further away than aMinClearance
|
||||
if( center2center - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius() >= aMinClearance )
|
||||
return true;
|
||||
|
||||
/* Here, pads are near and DRC depends on the pad shapes. We must compare distance using
|
||||
* a fine shape analysis.
|
||||
* Because a circle or oval shape is the easier shape to test, swap pads to have aRefPad be
|
||||
* a PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL. If aRefPad = TRAPEZOID and aPad = RECT, also swap.
|
||||
*/
|
||||
bool swap_pads;
|
||||
swap_pads = false;
|
||||
// JEY TODO:
|
||||
// TOM TODO: MTV only works as a proxy for actual-distance for convex shapes
|
||||
|
||||
// swap pads to make comparisons easier
|
||||
// Note also a ROUNDRECT pad with a corner radius = r can be considered as
|
||||
// a smaller RECT (size - 2*r) with a clearance increased by r
|
||||
// priority is aRefPad = ROUND then OVAL then RECT/ROUNDRECT then other
|
||||
if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_SHAPE_CIRCLE )
|
||||
VECTOR2I mtv;
|
||||
VECTOR2I maxMtv( 0, 0 );
|
||||
|
||||
for( const std::shared_ptr<SHAPE>& aShape : aRefPad->GetEffectiveShapes() )
|
||||
{
|
||||
// pad ref shape is here oval, rect, roundrect, chamfered rect, trapezoid or custom
|
||||
switch( aPad->GetShape() )
|
||||
for( const std::shared_ptr<SHAPE>& bShape : aPad->GetEffectiveShapes() )
|
||||
{
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
swap_pads = true;
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_OVAL:
|
||||
swap_pads = true;
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_RECT:
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
if( aRefPad->GetShape() != PAD_SHAPE_OVAL )
|
||||
swap_pads = true;
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
break;
|
||||
if( aShape->Collide( bShape.get(), aMinClearance, mtv ) )
|
||||
{
|
||||
if( mtv.SquaredEuclideanNorm() > maxMtv.SquaredEuclideanNorm() )
|
||||
maxMtv = mtv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( swap_pads )
|
||||
if( maxMtv.x > 0 || maxMtv.y > 0 )
|
||||
{
|
||||
std::swap( aRefPad, aPad );
|
||||
relativePadPos = -relativePadPos;
|
||||
*aActual = std::max( 0, aMinClearance - maxMtv.EuclideanNorm() );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool diag = true;
|
||||
|
||||
if( ( aRefPad->GetShape() == PAD_SHAPE_CIRCLE || aRefPad->GetShape() == PAD_SHAPE_OVAL ) )
|
||||
{
|
||||
/* Treat an oval pad as a line segment along the hole's major axis,
|
||||
* shortened by half its minor axis.
|
||||
* A circular pad is just a degenerate case of an oval hole.
|
||||
*/
|
||||
wxPoint refPadStart, refPadEnd;
|
||||
int refPadWidth;
|
||||
|
||||
aRefPad->GetOblongGeometry( aRefPad->GetSize(), &refPadStart, &refPadEnd, &refPadWidth );
|
||||
refPadStart += aRefPad->ShapePos();
|
||||
refPadEnd += aRefPad->ShapePos();
|
||||
|
||||
SEG refPadSeg( refPadStart, refPadEnd );
|
||||
diag = checkClearanceSegmToPad( refPadSeg, refPadWidth, aPad, aMinClearance, aActual );
|
||||
}
|
||||
else
|
||||
{
|
||||
int dist_extra = 0;
|
||||
|
||||
// corners of aRefPad (used only for rect/roundrect/trap pad)
|
||||
wxPoint polyref[4];
|
||||
// corners of aRefPad (used only for custom pad)
|
||||
SHAPE_POLY_SET polysetref;
|
||||
|
||||
if( aRefPad->GetShape() == PAD_SHAPE_ROUNDRECT )
|
||||
{
|
||||
int padRadius = aRefPad->GetRoundRectCornerRadius();
|
||||
dist_extra = padRadius;
|
||||
GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ), aRefPad->GetSize(),
|
||||
aRefPad->GetOrientation() );
|
||||
}
|
||||
else if( aRefPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
|
||||
{
|
||||
BOARD* board = aRefPad->GetBoard();
|
||||
int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
|
||||
|
||||
// The reference pad can be rotated. Calculate the rotated coordinates.
|
||||
// (note, the ref pad position is the origin of coordinates for this drc test)
|
||||
int padRadius = aRefPad->GetRoundRectCornerRadius();
|
||||
|
||||
TransformRoundChamferedRectToPolygon( polysetref, wxPoint( 0, 0 ), aRefPad->GetSize(),
|
||||
aRefPad->GetOrientation(),
|
||||
padRadius, aRefPad->GetChamferRectRatio(),
|
||||
aRefPad->GetChamferPositions(), maxError );
|
||||
}
|
||||
else if( aRefPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
polysetref.Append( aRefPad->GetCustomShapeAsPolygon() );
|
||||
|
||||
// The reference pad can be rotated. Calculate the rotated coordinates.
|
||||
// (note, the ref pad position is the origin of coordinates for this drc test)
|
||||
aRefPad->CustomShapeAsPolygonToBoardPosition( &polysetref, wxPoint( 0, 0 ),
|
||||
aRefPad->GetOrientation() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// BuildPadPolygon has meaning for rect a trapeziod shapes and returns the 4 corners.
|
||||
aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
|
||||
}
|
||||
|
||||
// corners of aPad (used only for rect/roundrect/trap pad)
|
||||
wxPoint polycompare[4];
|
||||
// corners of aPad (used only custom pad)
|
||||
SHAPE_POLY_SET polysetcompare;
|
||||
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
case PAD_SHAPE_RECT:
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
|
||||
{
|
||||
int padRadius = aPad->GetRoundRectCornerRadius();
|
||||
dist_extra = padRadius;
|
||||
GetRoundRectCornerCenters( polycompare, padRadius, relativePadPos, aPad->GetSize(),
|
||||
aPad->GetOrientation() );
|
||||
}
|
||||
else if( aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
|
||||
{
|
||||
BOARD* board = aRefPad->GetBoard();
|
||||
int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
|
||||
|
||||
// The pad to compare can be rotated. Calculate the rotated coordinates.
|
||||
// ( note, the pad to compare position is the relativePadPos for this drc test)
|
||||
int padRadius = aPad->GetRoundRectCornerRadius();
|
||||
|
||||
TransformRoundChamferedRectToPolygon( polysetcompare, relativePadPos,
|
||||
aPad->GetSize(), aPad->GetOrientation(),
|
||||
padRadius, aPad->GetChamferRectRatio(),
|
||||
aPad->GetChamferPositions(), maxError );
|
||||
}
|
||||
else if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
polysetcompare.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
|
||||
// The pad to compare can be rotated. Calculate the rotated coordinates.
|
||||
// ( note, the pad to compare position is the relativePadPos for this drc test)
|
||||
aPad->CustomShapeAsPolygonToBoardPosition( &polysetcompare, relativePadPos,
|
||||
aPad->GetOrientation() );
|
||||
}
|
||||
else
|
||||
{
|
||||
aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );
|
||||
|
||||
// Move aPad shape to relativePadPos
|
||||
for( int ii = 0; ii < 4; ii++ )
|
||||
polycompare[ii] += relativePadPos;
|
||||
}
|
||||
|
||||
// And now test polygons: We have 3 cases:
|
||||
// one poly is complex and the other is basic (has only 4 corners)
|
||||
// both polys are complex
|
||||
// both polys are basic (have only 4 corners) the most usual case
|
||||
if( polysetref.OutlineCount() && polysetcompare.OutlineCount() == 0)
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 );
|
||||
// And now test polygons:
|
||||
if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
|
||||
polycompare, 4, aMinClearance + dist_extra, aActual ) )
|
||||
{
|
||||
*aActual = std::max( 0, *aActual - dist_extra );
|
||||
diag = false;
|
||||
}
|
||||
}
|
||||
else if( polysetref.OutlineCount() == 0 && polysetcompare.OutlineCount())
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& cmppoly = polysetcompare.COutline( 0 );
|
||||
// And now test polygons:
|
||||
if( !poly2polyDRC((wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(),
|
||||
polyref, 4, aMinClearance + dist_extra, aActual ) )
|
||||
{
|
||||
*aActual = std::max( 0, *aActual - dist_extra );
|
||||
diag = false;
|
||||
}
|
||||
}
|
||||
else if( polysetref.OutlineCount() && polysetcompare.OutlineCount() )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 );
|
||||
const SHAPE_LINE_CHAIN& cmppoly = polysetcompare.COutline( 0 );
|
||||
|
||||
// And now test polygons:
|
||||
if( !poly2polyDRC((wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
|
||||
(wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(),
|
||||
aMinClearance + dist_extra, aActual ) )
|
||||
{
|
||||
*aActual = std::max( 0, *aActual - dist_extra );
|
||||
diag = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !poly2polyDRC( polyref, 4, polycompare, 4, aMinClearance + dist_extra, aActual ) )
|
||||
{
|
||||
*aActual = std::max( 0, *aActual - dist_extra );
|
||||
diag = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape %d" ), aPad->GetShape() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return diag;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -594,8 +594,14 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb )
|
|||
{
|
||||
fprintf( aFile, " POLYGON %g\n", pad->GetDrillSize().x / SCALE_FACTOR );
|
||||
|
||||
int ddx = pad->GetDelta().x / 2;
|
||||
int ddy = pad->GetDelta().y / 2;
|
||||
|
||||
wxPoint poly[4];
|
||||
pad->BuildPadPolygon( poly, wxSize( 0, 0 ), 0 );
|
||||
poly[0] = wxPoint( -dx + ddy, dy + ddx );
|
||||
poly[1] = wxPoint( dx - ddy, dy - ddx );
|
||||
poly[2] = wxPoint( dx + ddy, -dy + ddx );
|
||||
poly[3] = wxPoint( -dx - ddy, -dy - ddx );
|
||||
|
||||
for( int cur = 0; cur < 4; ++cur )
|
||||
{
|
||||
|
@ -613,7 +619,8 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb )
|
|||
{
|
||||
fprintf( aFile, " POLYGON %g\n", pad->GetDrillSize().x / SCALE_FACTOR );
|
||||
|
||||
const SHAPE_POLY_SET& outline = pad->GetCustomShapeAsPolygon();
|
||||
SHAPE_POLY_SET outline;
|
||||
pad->MergePrimitivesAsPolygon( &outline );
|
||||
|
||||
for( int jj = 0; jj < outline.OutlineCount(); ++jj )
|
||||
{
|
||||
|
|
|
@ -1151,7 +1151,7 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aTinLayer, D_P
|
|||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
{
|
||||
SHAPE_POLY_SET polySet;
|
||||
const int corner_radius = aPad->GetRoundRectCornerRadius( aPad->GetSize() );
|
||||
const int corner_radius = aPad->GetRoundRectCornerRadius();
|
||||
TransformRoundChamferedRectToPolygon( polySet, wxPoint( 0, 0 ), aPad->GetSize(),
|
||||
0.0, corner_radius, 0.0, 0, ARC_HIGH_DEF );
|
||||
std::vector< wxRealPoint > cornerList;
|
||||
|
|
|
@ -1479,8 +1479,8 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
|
|||
if( aPad->GetLocalClearance() != 0 )
|
||||
StrPrintf( &output, " (clearance %s)", FormatInternalUnits( aPad->GetLocalClearance() ).c_str() );
|
||||
|
||||
if( aPad->GetZoneConnection() != ZONE_CONNECTION::INHERITED )
|
||||
StrPrintf( &output, " (zone_connect %d)", static_cast<int>( aPad->GetZoneConnection() ) );
|
||||
if( aPad->GetEffectiveZoneConnection() != ZONE_CONNECTION::INHERITED )
|
||||
StrPrintf( &output, " (zone_connect %d)", static_cast<int>( aPad->GetEffectiveZoneConnection() ) );
|
||||
|
||||
if( aPad->GetThermalWidth() != 0 )
|
||||
StrPrintf( &output, " (thermal_width %s)", FormatInternalUnits( aPad->GetThermalWidth() ).c_str() );
|
||||
|
|
|
@ -146,7 +146,7 @@ void PAD_CS_PRIMITIVE::Rotate( const wxPoint& aRotCentre, double aAngle )
|
|||
* the shape is a polygon (can be with thick outline), segment, circle or arc
|
||||
*/
|
||||
|
||||
void D_PAD::AddPrimitivePoly( const SHAPE_POLY_SET& aPoly, int aThickness, bool aMergePrimitives )
|
||||
void D_PAD::AddPrimitivePoly( const SHAPE_POLY_SET& aPoly, int aThickness )
|
||||
{
|
||||
std::vector<wxPoint> points;
|
||||
|
||||
|
@ -158,39 +158,33 @@ void D_PAD::AddPrimitivePoly( const SHAPE_POLY_SET& aPoly, int aThickness, bool
|
|||
for( auto iter = poly_no_hole.CIterate(); iter; iter++ )
|
||||
points.emplace_back( iter->x, iter->y );
|
||||
|
||||
AddPrimitivePoly( points, aThickness, aMergePrimitives );
|
||||
AddPrimitivePoly( points, aThickness );
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AddPrimitivePoly( const std::vector<wxPoint>& aPoly, int aThickness,
|
||||
bool aMergePrimitives )
|
||||
void D_PAD::AddPrimitivePoly( const std::vector<wxPoint>& aPoly, int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_POLYGON );
|
||||
shape.m_Poly = aPoly;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
if( aMergePrimitives )
|
||||
MergePrimitivesAsPolygon();
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AddPrimitiveSegment( const wxPoint& aStart, const wxPoint& aEnd, int aThickness,
|
||||
bool aMergePrimitives )
|
||||
void D_PAD::AddPrimitiveSegment( const wxPoint& aStart, const wxPoint& aEnd, int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_SEGMENT );
|
||||
shape.m_Start = aStart;
|
||||
shape.m_End = aEnd;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
if( aMergePrimitives )
|
||||
MergePrimitivesAsPolygon();
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AddPrimitiveArc( const wxPoint& aCenter, const wxPoint& aStart, int aArcAngle,
|
||||
int aThickness, bool aMergePrimitives )
|
||||
int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_ARC );
|
||||
shape.m_Start = aCenter;
|
||||
|
@ -198,14 +192,12 @@ void D_PAD::AddPrimitiveArc( const wxPoint& aCenter, const wxPoint& aStart, int
|
|||
shape.m_ArcAngle = aArcAngle;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
if( aMergePrimitives )
|
||||
MergePrimitivesAsPolygon();
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AddPrimitiveCurve( const wxPoint& aStart, const wxPoint& aEnd, const wxPoint& aCtrl1,
|
||||
const wxPoint& aCtrl2, int aThickness, bool aMergePrimitives )
|
||||
const wxPoint& aCtrl2, int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_CURVE );
|
||||
shape.m_Start = aStart;
|
||||
|
@ -214,41 +206,33 @@ void D_PAD::AddPrimitiveCurve( const wxPoint& aStart, const wxPoint& aEnd, const
|
|||
shape.m_Ctrl2 = aCtrl2;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
if( aMergePrimitives )
|
||||
MergePrimitivesAsPolygon();
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AddPrimitiveCircle( const wxPoint& aCenter, int aRadius, int aThickness,
|
||||
bool aMergePrimitives )
|
||||
void D_PAD::AddPrimitiveCircle( const wxPoint& aCenter, int aRadius, int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_CIRCLE );
|
||||
shape.m_Start = aCenter;
|
||||
shape.m_Radius = aRadius;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
if( aMergePrimitives )
|
||||
MergePrimitivesAsPolygon();
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AddPrimitiveRect( const wxPoint& aStart, const wxPoint& aEnd, int aThickness,
|
||||
bool aMergePrimitives )
|
||||
void D_PAD::AddPrimitiveRect( const wxPoint& aStart, const wxPoint& aEnd, int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_RECT );
|
||||
shape.m_Start = aStart;
|
||||
shape.m_End = aEnd;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
if( aMergePrimitives )
|
||||
MergePrimitivesAsPolygon();
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
|
||||
bool D_PAD::SetPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList )
|
||||
void D_PAD::SetPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList )
|
||||
{
|
||||
// clear old list
|
||||
m_basicShapes.clear();
|
||||
|
@ -257,17 +241,16 @@ bool D_PAD::SetPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList
|
|||
if( aPrimitivesList.size() )
|
||||
m_basicShapes = aPrimitivesList;
|
||||
|
||||
// Only one polygon is expected (pad area = only one copper area)
|
||||
return MergePrimitivesAsPolygon();
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
|
||||
bool D_PAD::AddPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList )
|
||||
void D_PAD::AddPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList )
|
||||
{
|
||||
for( const auto& prim : aPrimitivesList )
|
||||
m_basicShapes.push_back( prim );
|
||||
|
||||
return MergePrimitivesAsPolygon();
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -275,44 +258,44 @@ bool D_PAD::AddPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList
|
|||
void D_PAD::DeletePrimitivesList()
|
||||
{
|
||||
m_basicShapes.clear();
|
||||
m_customShapeAsPolygon.RemoveAllContours();
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
|
||||
|
||||
bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError )
|
||||
|
||||
void D_PAD::addCustomPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const
|
||||
{
|
||||
SHAPE_POLY_SET aux_polyset;
|
||||
SHAPE_POLY_SET polyset;
|
||||
|
||||
for( PAD_CS_PRIMITIVE& bshape : m_basicShapes )
|
||||
for( const PAD_CS_PRIMITIVE& bshape : m_basicShapes )
|
||||
{
|
||||
switch( bshape.m_Shape )
|
||||
{
|
||||
case S_CURVE:
|
||||
{
|
||||
std::vector<wxPoint> ctrlPoints = { bshape.m_Start, bshape.m_Ctrl1, bshape.m_Ctrl2, bshape.m_End };
|
||||
std::vector<wxPoint> ctrlPoints = { bshape.m_Start, bshape.m_Ctrl1, bshape.m_Ctrl2,
|
||||
bshape.m_End };
|
||||
BEZIER_POLY converter( ctrlPoints );
|
||||
std::vector< wxPoint> poly;
|
||||
converter.GetPoly( poly, bshape.m_Thickness );
|
||||
|
||||
for( unsigned ii = 1; ii < poly.size(); ii++ )
|
||||
{
|
||||
TransformSegmentToPolygon(
|
||||
aux_polyset, poly[ ii - 1 ], poly[ ii ], aError, bshape.m_Thickness );
|
||||
TransformSegmentToPolygon( polyset, poly[ ii - 1 ], poly[ ii ], aError,
|
||||
bshape.m_Thickness );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case S_SEGMENT: // usual segment : line with rounded ends
|
||||
{
|
||||
TransformSegmentToPolygon( aux_polyset, bshape.m_Start, bshape.m_End, aError,
|
||||
TransformSegmentToPolygon( polyset, bshape.m_Start, bshape.m_End, aError,
|
||||
bshape.m_Thickness );
|
||||
break;
|
||||
}
|
||||
|
||||
case S_ARC: // Arc with rounded ends
|
||||
{
|
||||
TransformArcToPolygon( aux_polyset, bshape.m_Start, bshape.m_End, bshape.m_ArcAngle,
|
||||
TransformArcToPolygon( polyset, bshape.m_Start, bshape.m_End, bshape.m_ArcAngle,
|
||||
aError, bshape.m_Thickness );
|
||||
break;
|
||||
}
|
||||
|
@ -320,80 +303,63 @@ bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError )
|
|||
case S_CIRCLE: // ring or circle
|
||||
{
|
||||
if( bshape.m_Thickness ) // ring
|
||||
TransformRingToPolygon( aux_polyset, bshape.m_Start, bshape.m_Radius, aError,
|
||||
TransformRingToPolygon( polyset, bshape.m_Start, bshape.m_Radius, aError,
|
||||
bshape.m_Thickness );
|
||||
else // Filled circle
|
||||
TransformCircleToPolygon( aux_polyset, bshape.m_Start, bshape.m_Radius, aError );
|
||||
TransformCircleToPolygon( polyset, bshape.m_Start, bshape.m_Radius, aError );
|
||||
break;
|
||||
}
|
||||
|
||||
case S_RECT:
|
||||
bshape.m_Poly.clear();
|
||||
bshape.m_Poly.emplace_back( bshape.m_Start );
|
||||
bshape.m_Poly.emplace_back( bshape.m_End.x, bshape.m_Start.y );
|
||||
bshape.m_Poly.emplace_back( bshape.m_End );
|
||||
bshape.m_Poly.emplace_back( bshape.m_Start.x, bshape.m_End.y );
|
||||
|
||||
KI_FALLTHROUGH;
|
||||
|
||||
case S_POLYGON: // polygon
|
||||
{
|
||||
if( bshape.m_Poly.size() < 2 )
|
||||
break; // Malformed polygon.
|
||||
SHAPE_POLY_SET poly;
|
||||
poly.NewOutline();
|
||||
|
||||
// Insert the polygon:
|
||||
const std::vector< wxPoint>& poly = bshape.m_Poly;
|
||||
aux_polyset.NewOutline();
|
||||
|
||||
if( bshape.m_Thickness )
|
||||
if( bshape.m_Shape == S_RECT )
|
||||
{
|
||||
SHAPE_POLY_SET polyset;
|
||||
polyset.NewOutline();
|
||||
|
||||
for( const wxPoint& pt : poly )
|
||||
polyset.Append( pt.x, pt.y );
|
||||
|
||||
int numSegs = std::max( GetArcToSegmentCount( bshape.m_Thickness / 2, aError, 360.0 ), 6 );
|
||||
polyset.Inflate( bshape.m_Thickness / 2, numSegs );
|
||||
|
||||
aux_polyset.Append( polyset );
|
||||
poly.Append( bshape.m_Start );
|
||||
poly.Append( bshape.m_End.x, bshape.m_Start.y );
|
||||
poly.Append( bshape.m_End );
|
||||
poly.Append( bshape.m_Start.x, bshape.m_End.y );
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const wxPoint& pt : poly )
|
||||
aux_polyset.Append( pt.x, pt.y );
|
||||
for( const wxPoint& pt : bshape.m_Poly )
|
||||
poly.Append( pt );
|
||||
}
|
||||
|
||||
if( bshape.m_Shape == S_RECT )
|
||||
bshape.m_Poly.clear();
|
||||
if( bshape.m_Thickness )
|
||||
{
|
||||
int numSegs = std::max( GetArcToSegmentCount( bshape.m_Thickness / 2, aError, 360.0 ), 6 );
|
||||
poly.Inflate( bshape.m_Thickness / 2, numSegs );
|
||||
}
|
||||
|
||||
// Insert the polygon:
|
||||
polyset.NewOutline();
|
||||
polyset.Append( poly );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// un-handled primitive
|
||||
wxASSERT_MSG( false, wxT( "D_PAD::buildCustomPadPolygon not implemented for "
|
||||
+ BOARD_ITEM::ShowShape( bshape.m_Shape ) ) );
|
||||
wxASSERT_MSG( false, "D_PAD::addCustomPadPrimitivesToPolygon not implemented for "
|
||||
+ BOARD_ITEM::ShowShape( bshape.m_Shape ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aux_polyset.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
polyset.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
// Merge all polygons with the initial pad anchor shape
|
||||
if( aux_polyset.OutlineCount() )
|
||||
if( polyset.OutlineCount() )
|
||||
{
|
||||
aMergedPolygon->BooleanAdd( aux_polyset, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||
aMergedPolygon->BooleanAdd( polyset, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||
aMergedPolygon->Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||
}
|
||||
|
||||
return aMergedPolygon->OutlineCount() <= 1;
|
||||
}
|
||||
|
||||
/* Merge all basic shapes, converted to a polygon in one polygon,
|
||||
* return true if OK, false in there is more than one polygon
|
||||
* in aMergedPolygon
|
||||
*/
|
||||
bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon )
|
||||
void D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon ) const
|
||||
{
|
||||
auto board = GetBoard();
|
||||
int maxError = ARC_HIGH_DEF;
|
||||
|
@ -401,58 +367,35 @@ bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon )
|
|||
if( board )
|
||||
maxError = board->GetDesignSettings().m_MaxError;
|
||||
|
||||
// if aMergedPolygon == NULL, use m_customShapeAsPolygon as target
|
||||
|
||||
if( !aMergedPolygon )
|
||||
aMergedPolygon = &m_customShapeAsPolygon;
|
||||
|
||||
aMergedPolygon->RemoveAllContours();
|
||||
|
||||
// Add the anchor pad shape in aMergedPolygon, others in aux_polyset:
|
||||
// The anchor pad is always at 0,0
|
||||
switch( GetAnchorPadShape() )
|
||||
{
|
||||
default:
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
TransformCircleToPolygon( *aMergedPolygon, wxPoint( 0, 0 ), GetSize().x / 2, maxError );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_RECT:
|
||||
{
|
||||
SHAPE_RECT rect( -GetSize().x / 2, -GetSize().y / 2, GetSize().x, GetSize().y );
|
||||
aMergedPolygon->AddOutline( rect.Outline() );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
TransformCircleToPolygon( *aMergedPolygon, wxPoint( 0, 0 ), GetSize().x / 2, maxError );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !buildCustomPadPolygon( aMergedPolygon, maxError ) )
|
||||
return false;
|
||||
|
||||
m_boundingRadius = -1; // The current bounding radius is no longer valid.
|
||||
|
||||
return aMergedPolygon->OutlineCount() <= 1;
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::CustomShapeAsPolygonToBoardPosition( SHAPE_POLY_SET * aMergedPolygon,
|
||||
wxPoint aPosition, double aRotation ) const
|
||||
{
|
||||
if( aMergedPolygon->OutlineCount() == 0 )
|
||||
return;
|
||||
|
||||
// Move, rotate, ... coordinates in aMergedPolygon according to the
|
||||
// pad position and orientation
|
||||
aMergedPolygon->Rotate( -DECIDEG2RAD( aRotation ) );
|
||||
aMergedPolygon->Move( VECTOR2I( aPosition ) );
|
||||
addCustomPadPrimitivesToPolygon( aMergedPolygon, maxError );
|
||||
}
|
||||
|
||||
|
||||
bool D_PAD::GetBestAnchorPosition( VECTOR2I& aPos )
|
||||
{
|
||||
SHAPE_POLY_SET poly;
|
||||
addCustomPadPrimitivesToPolygon( &poly, ARC_LOW_DEF );
|
||||
|
||||
if( !buildCustomPadPolygon( &poly, ARC_LOW_DEF ) )
|
||||
if( poly.OutlineCount() > 1 )
|
||||
return false;
|
||||
|
||||
const int minSteps = 10;
|
||||
|
|
|
@ -44,7 +44,9 @@
|
|||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/shape_circle.h>
|
||||
#include <geometry/shape_simple.h>
|
||||
|
||||
using namespace KIGFX;
|
||||
|
||||
|
@ -790,161 +792,59 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|
|||
// Choose drawing settings depending on if we are drawing a pad itself or a hole
|
||||
if( aLayer == LAYER_PADS_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
|
||||
{
|
||||
m_gal->Save();
|
||||
m_gal->Translate( VECTOR2D( aPad->GetPosition() ) );
|
||||
m_gal->Rotate( -aPad->GetOrientationRadians() );
|
||||
const std::shared_ptr<SHAPE_SEGMENT>& seg = aPad->GetEffectiveHoleShape();
|
||||
|
||||
// Drawing hole: has same shape as PAD_CIRCLE or PAD_OVAL
|
||||
size = getDrillSize( aPad ) / 2.0;
|
||||
|
||||
if( getDrillShape( aPad ) == PAD_DRILL_SHAPE_OBLONG )
|
||||
{
|
||||
if( size.y >= size.x )
|
||||
{
|
||||
m = ( size.y - size.x );
|
||||
n = size.x;
|
||||
|
||||
m_gal->DrawArc( VECTOR2D( 0, -m ), n, -M_PI, 0 );
|
||||
m_gal->DrawArc( VECTOR2D( 0, m ), n, M_PI, 0 );
|
||||
|
||||
if( m_pcbSettings.m_sketchMode[LAYER_PADS_TH] )
|
||||
{
|
||||
m_gal->DrawLine( VECTOR2D( -n, -m ), VECTOR2D( -n, m ) );
|
||||
m_gal->DrawLine( VECTOR2D( n, -m ), VECTOR2D( n, m ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gal->DrawRectangle( VECTOR2D( -n, -m ), VECTOR2D( n, m ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m = ( size.x - size.y );
|
||||
n = size.y;
|
||||
m_gal->DrawArc( VECTOR2D( -m, 0 ), n, M_PI / 2, 3 * M_PI / 2 );
|
||||
m_gal->DrawArc( VECTOR2D( m, 0 ), n, M_PI / 2, -M_PI / 2 );
|
||||
|
||||
if( m_pcbSettings.m_sketchMode[LAYER_PADS_TH] )
|
||||
{
|
||||
m_gal->DrawLine( VECTOR2D( -m, -n ), VECTOR2D( m, -n ) );
|
||||
m_gal->DrawLine( VECTOR2D( -m, n ), VECTOR2D( m, n ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gal->DrawRectangle( VECTOR2D( -m, -n ), VECTOR2D( m, n ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gal->DrawCircle( VECTOR2D( 0.0, 0.0 ), size.x );
|
||||
}
|
||||
|
||||
m_gal->Restore();
|
||||
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, seg->GetWidth() );
|
||||
}
|
||||
else
|
||||
{
|
||||
SHAPE_POLY_SET polySet;
|
||||
wxSize pad_size = aPad->GetSize();
|
||||
wxSize margin;
|
||||
|
||||
switch( aLayer )
|
||||
{
|
||||
case F_Mask:
|
||||
case B_Mask:
|
||||
{
|
||||
int clearance = aPad->GetSolderMaskMargin();
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
|
||||
{
|
||||
int radius = (aPad->GetSize().x/2) + clearance;
|
||||
m_gal->DrawCircle( VECTOR2D( aPad->ShapePos() ), radius );
|
||||
}
|
||||
else if( aPad->GetShape() == PAD_SHAPE_OVAL )
|
||||
{
|
||||
if( aPad->GetSize().x == aPad->GetSize().y )
|
||||
{
|
||||
int radius = (aPad->GetSize().x/2) + clearance;
|
||||
m_gal->DrawCircle( VECTOR2D( aPad->ShapePos() ), radius );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxPoint seg_start, seg_end;
|
||||
aPad->BuildSegmentFromOvalShape( seg_start, seg_end,
|
||||
aPad->GetOrientation(),
|
||||
wxSize( 0, 0 ) );
|
||||
int seg_width = std::min( aPad->GetSize().x, aPad->GetSize().y )
|
||||
+ 2*clearance;
|
||||
m_gal->DrawSegment( VECTOR2D( aPad->ShapePos()+seg_start ),
|
||||
VECTOR2D( aPad->ShapePos()+seg_end ),
|
||||
seg_width );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aPad->TransformShapeWithClearanceToPolygon( polySet, clearance );
|
||||
m_gal->DrawPolygon( polySet );
|
||||
}
|
||||
}
|
||||
margin.x = margin.y = aPad->GetSolderMaskMargin();
|
||||
break;
|
||||
|
||||
case F_Paste:
|
||||
case B_Paste:
|
||||
{
|
||||
wxSize pad_size = aPad->GetSize();
|
||||
wxSize margin = aPad->GetSolderPasteMargin();
|
||||
const_cast<D_PAD*>(aPad)->SetSize( pad_size + margin + margin );
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
|
||||
m_gal->DrawCircle( VECTOR2D( aPad->ShapePos() ), aPad->GetSize().x/2 );
|
||||
else if( aPad->GetShape() == PAD_SHAPE_OVAL )
|
||||
{
|
||||
if( aPad->GetSize().x == aPad->GetSize().y )
|
||||
m_gal->DrawCircle( VECTOR2D( aPad->ShapePos() ), aPad->GetSize().x/2 );
|
||||
else
|
||||
{
|
||||
wxPoint seg_start, seg_end;
|
||||
aPad->BuildSegmentFromOvalShape( seg_start, seg_end,
|
||||
aPad->GetOrientation(),
|
||||
wxSize( 0, 0 ) );
|
||||
int seg_width = std::min( aPad->GetSize().x, aPad->GetSize().y );
|
||||
m_gal->DrawSegment( VECTOR2D( aPad->ShapePos()+seg_start ),
|
||||
VECTOR2D( aPad->ShapePos()+seg_end ),
|
||||
seg_width );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aPad->TransformShapeWithClearanceToPolygon( polySet, 0 );
|
||||
m_gal->DrawPolygon( polySet );
|
||||
}
|
||||
const_cast<D_PAD*>(aPad)->SetSize( pad_size );
|
||||
}
|
||||
margin = aPad->GetSolderPasteMargin();
|
||||
break;
|
||||
|
||||
default:
|
||||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
|
||||
m_gal->DrawCircle( VECTOR2D( aPad->ShapePos() ), aPad->GetSize().x/2 );
|
||||
else if( aPad->GetShape() == PAD_SHAPE_OVAL )
|
||||
{
|
||||
if( aPad->GetSize().x == aPad->GetSize().y )
|
||||
m_gal->DrawCircle( VECTOR2D( aPad->ShapePos() ), aPad->GetSize().x/2 );
|
||||
else
|
||||
{
|
||||
wxPoint seg_start, seg_end;
|
||||
aPad->BuildSegmentFromOvalShape( seg_start, seg_end,
|
||||
aPad->GetOrientation(),
|
||||
wxSize( 0, 0 ) );
|
||||
m_gal->DrawSegment( VECTOR2D( aPad->ShapePos()+seg_start ),
|
||||
VECTOR2D( aPad->ShapePos()+seg_end ),
|
||||
std::min( aPad->GetSize().x, aPad->GetSize().y ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aPad->TransformShapeWithClearanceToPolygon( polySet, 0 );
|
||||
m_gal->DrawPolygon( polySet );
|
||||
}
|
||||
margin.x = margin.y = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if( margin.x != margin.y )
|
||||
{
|
||||
const_cast<D_PAD*>( aPad )->SetSize( pad_size + margin + margin );
|
||||
margin.x = margin.y = 0;
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<SHAPE>>& shapes = aPad->GetEffectiveShapes();
|
||||
|
||||
if( shapes.size() == 1 && shapes[0]->Type() == SH_SEGMENT )
|
||||
{
|
||||
const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shapes[0].get();
|
||||
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, seg->GetWidth() + 2 * margin.x );
|
||||
}
|
||||
else if( shapes.size() == 1 && shapes[0]->Type() == SH_CIRCLE )
|
||||
{
|
||||
const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shapes[0].get();
|
||||
m_gal->DrawCircle( circle->GetCenter(), circle->GetRadius() + margin.x );
|
||||
}
|
||||
else
|
||||
{
|
||||
SHAPE_POLY_SET polySet;
|
||||
aPad->TransformShapeWithClearanceToPolygon( polySet, margin.x );
|
||||
m_gal->DrawPolygon( polySet );
|
||||
}
|
||||
|
||||
if( aPad->GetSize() != pad_size )
|
||||
const_cast<D_PAD*>( aPad )->SetSize( pad_size );
|
||||
}
|
||||
|
||||
// Clearance outlines
|
||||
|
@ -961,31 +861,17 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|
|||
m_gal->SetStrokeColor( color );
|
||||
int clearance = aPad->GetClearance();
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
|
||||
{
|
||||
int radius = (aPad->GetSize().x/2) + clearance;
|
||||
m_gal->DrawCircle( VECTOR2D( aPad->ShapePos() ), radius );
|
||||
}
|
||||
else if( aPad->GetShape() == PAD_SHAPE_OVAL )
|
||||
{
|
||||
if( aPad->GetSize().x == aPad->GetSize().y )
|
||||
{
|
||||
int radius = (aPad->GetSize().x/2) + clearance;
|
||||
m_gal->DrawCircle( VECTOR2D( aPad->ShapePos() ), radius );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxPoint seg_start, seg_end;
|
||||
const std::vector<std::shared_ptr<SHAPE>>& shapes = aPad->GetEffectiveShapes();
|
||||
|
||||
aPad->BuildSegmentFromOvalShape( seg_start, seg_end,
|
||||
aPad->GetOrientation(),
|
||||
wxSize( 0, 0 ) );
|
||||
int seg_width = std::min( aPad->GetSize().x, aPad->GetSize().y )
|
||||
+ 2*clearance;
|
||||
m_gal->DrawSegment( VECTOR2D( aPad->ShapePos()+seg_start ),
|
||||
VECTOR2D( aPad->ShapePos()+seg_end ),
|
||||
seg_width );
|
||||
}
|
||||
if( shapes.size() == 1 && shapes[0]->Type() == SH_SEGMENT )
|
||||
{
|
||||
const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shapes[0].get();
|
||||
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, seg->GetWidth() + 2 * clearance );
|
||||
}
|
||||
else if( shapes.size() == 1 && shapes[0]->Type() == SH_CIRCLE )
|
||||
{
|
||||
const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shapes[0].get();
|
||||
m_gal->DrawCircle( circle->GetCenter(), circle->GetRadius() + clearance );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -3352,33 +3352,33 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent )
|
|||
case T_gr_arc:
|
||||
dummysegm = parseDRAWSEGMENT();
|
||||
pad->AddPrimitiveArc( dummysegm->GetCenter(), dummysegm->GetArcStart(),
|
||||
dummysegm->GetAngle(), dummysegm->GetWidth(), false );
|
||||
dummysegm->GetAngle(), dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
case T_gr_line:
|
||||
dummysegm = parseDRAWSEGMENT();
|
||||
pad->AddPrimitiveSegment( dummysegm->GetStart(), dummysegm->GetEnd(),
|
||||
dummysegm->GetWidth(), false );
|
||||
dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
case T_gr_circle:
|
||||
dummysegm = parseDRAWSEGMENT( true ); // Circles with 0 thickness are allowed
|
||||
// ( filled circles )
|
||||
pad->AddPrimitiveCircle( dummysegm->GetCenter(), dummysegm->GetRadius(),
|
||||
dummysegm->GetWidth(), false );
|
||||
dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
case T_gr_rect:
|
||||
dummysegm = parseDRAWSEGMENT( true );
|
||||
pad->AddPrimitiveRect( dummysegm->GetStart(), dummysegm->GetEnd(),
|
||||
dummysegm->GetWidth(), false );
|
||||
dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
|
||||
case T_gr_poly:
|
||||
dummysegm = parseDRAWSEGMENT();
|
||||
pad->AddPrimitivePoly( dummysegm->BuildPolyPointsList(),
|
||||
dummysegm->GetWidth(), false );
|
||||
dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
case T_gr_curve:
|
||||
|
@ -3386,7 +3386,7 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent )
|
|||
pad->AddPrimitiveCurve( dummysegm->GetStart(), dummysegm->GetEnd(),
|
||||
dummysegm->GetBezControl1(),
|
||||
dummysegm->GetBezControl2(),
|
||||
dummysegm->GetWidth(), false );
|
||||
dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -3411,10 +3411,6 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent )
|
|||
}
|
||||
}
|
||||
|
||||
// Be sure the custom shape polygon is built:
|
||||
if( pad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
pad->MergePrimitivesAsPolygon();
|
||||
|
||||
return pad.release();
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <base_struct.h>
|
||||
#include <gr_text.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <trigo.h>
|
||||
#include <pcb_base_frame.h>
|
||||
#include <macros.h>
|
||||
|
@ -249,70 +250,6 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
|||
continue;
|
||||
}
|
||||
|
||||
wxSize margin;
|
||||
double width_adj = 0;
|
||||
|
||||
if( onCopperLayer )
|
||||
width_adj = itemplotter.getFineWidthAdj();
|
||||
|
||||
if( onSolderMaskLayer )
|
||||
margin.x = margin.y = pad->GetSolderMaskMargin();
|
||||
|
||||
if( onSolderPasteLayer )
|
||||
margin = pad->GetSolderPasteMargin();
|
||||
|
||||
// Now offset the pad size by margin + width_adj
|
||||
// this is easy for most shapes, but not for a trapezoid or a custom shape
|
||||
wxSize padPlotsSize;
|
||||
wxSize extraSize = margin * 2;
|
||||
extraSize.x += width_adj;
|
||||
extraSize.y += width_adj;
|
||||
|
||||
// Store these parameters that can be modified to plot inflated/deflated pads shape
|
||||
wxSize deltaSize = pad->GetDelta(); // has meaning only for trapezoidal pads
|
||||
PAD_SHAPE_T padShape = pad->GetShape();
|
||||
double padCornerRadius = pad->GetRoundRectCornerRadius();
|
||||
|
||||
if( pad->GetShape() == PAD_SHAPE_TRAPEZOID )
|
||||
{ // The easy way is to use BuildPadPolygon to calculate
|
||||
// size and delta of the trapezoidal pad after offseting:
|
||||
wxPoint coord[4];
|
||||
pad->BuildPadPolygon( coord, extraSize/2, 0.0 );
|
||||
// Calculate the size and delta from polygon corners coordinates:
|
||||
// coord[0] is the lower left
|
||||
// coord[1] is the upper left
|
||||
// coord[2] is the upper right
|
||||
// coord[3] is the lower right
|
||||
|
||||
// the size is the distance between middle of segments
|
||||
// (left/right or top/bottom)
|
||||
// size X is the dist between left and right middle points:
|
||||
padPlotsSize.x = ( ( -coord[0].x + coord[3].x ) // the lower segment X length
|
||||
+ ( -coord[1].x + coord[2].x ) ) // the upper segment X length
|
||||
/ 2; // the Y size is the half sum
|
||||
// size Y is the dist between top and bottom middle points:
|
||||
padPlotsSize.y = ( ( coord[0].y - coord[1].y ) // the left segment Y lenght
|
||||
+ ( coord[3].y - coord[2].y ) ) // the right segment Y lenght
|
||||
/ 2; // the Y size is the half sum
|
||||
|
||||
// calculate the delta ( difference of lenght between 2 opposite edges )
|
||||
// The delta.x is the delta along the X axis, therefore the delta of Y lenghts
|
||||
wxSize delta;
|
||||
|
||||
if( coord[0].y != coord[3].y )
|
||||
delta.x = coord[0].y - coord[3].y;
|
||||
else
|
||||
delta.y = coord[1].x - coord[0].x;
|
||||
|
||||
pad->SetDelta( delta );
|
||||
}
|
||||
else
|
||||
padPlotsSize = pad->GetSize() + extraSize;
|
||||
|
||||
// Don't draw a null size item :
|
||||
if( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 )
|
||||
continue;
|
||||
|
||||
COLOR4D color = COLOR4D::BLACK;
|
||||
|
||||
if( pad->GetLayerSet()[B_Cu] )
|
||||
|
@ -326,8 +263,30 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
|||
else if( sketchPads && aLayerMask[B_Fab] )
|
||||
color = aPlotOpt.ColorSettings()->GetColor( B_Fab );
|
||||
|
||||
// Temporary set the pad size to the required plot size:
|
||||
wxSize tmppadsize = pad->GetSize();
|
||||
wxSize margin;
|
||||
int width_adj = 0;
|
||||
|
||||
if( onCopperLayer )
|
||||
width_adj = itemplotter.getFineWidthAdj();
|
||||
|
||||
if( onSolderMaskLayer )
|
||||
margin.x = margin.y = pad->GetSolderMaskMargin();
|
||||
|
||||
if( onSolderPasteLayer )
|
||||
margin = pad->GetSolderPasteMargin();
|
||||
|
||||
// Now offset the pad size by margin + width_adj
|
||||
wxSize padPlotsSize = pad->GetSize() + margin * 2 + wxSize( width_adj, width_adj );
|
||||
|
||||
// Store these parameters that can be modified to plot inflated/deflated pads shape
|
||||
PAD_SHAPE_T padShape = pad->GetShape();
|
||||
wxSize padSize = pad->GetSize();
|
||||
wxSize padDelta = pad->GetDelta(); // has meaning only for trapezoidal pads
|
||||
double padCornerRadius = pad->GetRoundRectCornerRadius();
|
||||
|
||||
// Don't draw a null size item :
|
||||
if( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 )
|
||||
continue;
|
||||
|
||||
switch( pad->GetShape() )
|
||||
{
|
||||
|
@ -348,14 +307,26 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
|||
if( margin.x > 0 )
|
||||
{
|
||||
pad->SetShape( PAD_SHAPE_ROUNDRECT );
|
||||
pad->SetSize( padPlotsSize );
|
||||
pad->SetRoundRectCornerRadius( margin.x );
|
||||
}
|
||||
KI_FALLTHROUGH;
|
||||
|
||||
pad->SetSize( padPlotsSize );
|
||||
itemplotter.PlotPad( pad, color, padPlotMode );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
{
|
||||
wxSize scale( padPlotsSize.x / padSize.x, padPlotsSize.y / padSize.y );
|
||||
pad->SetDelta( wxSize( padDelta.x * scale.x, padDelta.y * scale.y ) );
|
||||
|
||||
pad->SetSize( padPlotsSize );
|
||||
itemplotter.PlotPad( pad, color, padPlotMode );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
// Chamfer and rounding are stored as a percent and so don't need scaling
|
||||
pad->SetSize( padPlotsSize );
|
||||
itemplotter.PlotPad( pad, color, padPlotMode );
|
||||
break;
|
||||
|
@ -373,8 +344,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
|||
int numSegs = std::max( GetArcToSegmentCount( margin.x, maxError, 360.0 ), 6 );
|
||||
shape.InflateWithLinkedHoles( margin.x, numSegs, SHAPE_POLY_SET::PM_FAST );
|
||||
dummy.DeletePrimitivesList();
|
||||
dummy.AddPrimitivePoly( shape, 0, false );
|
||||
dummy.MergePrimitivesAsPolygon();
|
||||
dummy.AddPrimitivePoly( shape, 0 );
|
||||
|
||||
// Be sure the anchor pad is not bigger than the deflated shape because this
|
||||
// anchor will be added to the pad shape when plotting the pad. So now the
|
||||
|
@ -388,8 +358,8 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
|||
}
|
||||
|
||||
// Restore the pad parameters modified by the plot code
|
||||
pad->SetSize( tmppadsize );
|
||||
pad->SetDelta( deltaSize );
|
||||
pad->SetSize( padSize );
|
||||
pad->SetDelta( padDelta );
|
||||
pad->SetShape( padShape );
|
||||
pad->SetRoundRectCornerRadius( padCornerRadius );
|
||||
}
|
||||
|
@ -630,7 +600,6 @@ static const PCB_LAYER_ID plot_seq[] = {
|
|||
void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||
const PCB_PLOT_PARAMS& aPlotOpt )
|
||||
{
|
||||
|
||||
BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
|
||||
itemplotter.SetLayerSet( aLayerMask );
|
||||
|
||||
|
@ -646,7 +615,7 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
|||
outlines.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
// Plot outlines
|
||||
std::vector< wxPoint > cornerList;
|
||||
std::vector<wxPoint> cornerList;
|
||||
|
||||
// Now we have one or more basic polygons: plot each polygon
|
||||
for( int ii = 0; ii < outlines.OutlineCount(); ii++ )
|
||||
|
@ -673,9 +642,9 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
|||
int smallDrill = (aPlotOpt.GetDrillMarksType() == PCB_PLOT_PARAMS::SMALL_DRILL_SHAPE)
|
||||
? SMALL_DRILL : INT_MAX;
|
||||
|
||||
for( auto module : aBoard->Modules() )
|
||||
for( MODULE* module : aBoard->Modules() )
|
||||
{
|
||||
for( auto pad : module->Pads() )
|
||||
for( D_PAD* pad : module->Pads() )
|
||||
{
|
||||
wxSize hole = pad->GetDrillSize();
|
||||
|
||||
|
@ -690,19 +659,17 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
|||
else
|
||||
{
|
||||
// Note: small drill marks have no significance when applied to slots
|
||||
wxPoint drl_start, drl_end;
|
||||
int width;
|
||||
|
||||
pad->GetOblongGeometry( pad->GetDrillSize(), &drl_start, &drl_end, &width );
|
||||
aPlotter->ThickSegment( pad->GetPosition() + drl_start,
|
||||
pad->GetPosition() + drl_end, width, SKETCH, NULL );
|
||||
const std::shared_ptr<SHAPE_SEGMENT>& seg = pad->GetEffectiveHoleShape();
|
||||
aPlotter->ThickSegment( (wxPoint) seg->GetSeg().A,
|
||||
(wxPoint) seg->GetSeg().B,
|
||||
seg->GetWidth(), SKETCH, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Plot vias holes
|
||||
for( auto track : aBoard->Tracks() )
|
||||
for( TRACK* track : aBoard->Tracks() )
|
||||
{
|
||||
const VIA* via = dyn_cast<const VIA*>( track );
|
||||
|
||||
|
|
|
@ -224,13 +224,9 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, COLOR4D aColor, EDA_DRAW_MODE_T aPl
|
|||
aPad->GetOrientation(), aPlotMode, &gbr_metadata );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
{
|
||||
wxPoint coord[4];
|
||||
aPad->BuildPadPolygon( coord, wxSize(0,0), 0 );
|
||||
m_plotter->FlashPadTrapez( shape_pos, coord,
|
||||
aPad->GetOrientation(), aPlotMode, &gbr_metadata );
|
||||
}
|
||||
case PAD_SHAPE_RECT:
|
||||
m_plotter->FlashPadRect( shape_pos, aPad->GetSize(), aPad->GetOrientation(), aPlotMode,
|
||||
&gbr_metadata );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
|
@ -238,39 +234,20 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, COLOR4D aColor, EDA_DRAW_MODE_T aPl
|
|||
aPad->GetOrientation(), aPlotMode, &gbr_metadata );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
{
|
||||
SHAPE_POLY_SET polygons;
|
||||
const int corner_radius = aPad->GetRoundRectCornerRadius( aPad->GetSize() );
|
||||
TransformRoundChamferedRectToPolygon( polygons, shape_pos, aPad->GetSize(),
|
||||
aPad->GetOrientation(), corner_radius, aPad->GetChamferRectRatio(),
|
||||
aPad->GetChamferPositions(), m_board->GetDesignSettings().m_MaxError );
|
||||
|
||||
if( polygons.OutlineCount() == 0 )
|
||||
break;
|
||||
|
||||
int min_dim = std::min( aPad->GetSize().x, aPad->GetSize().y ) /2;
|
||||
m_plotter->FlashPadCustom( shape_pos,wxSize( min_dim, min_dim ), &polygons, aPlotMode, &gbr_metadata );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET polygons;
|
||||
aPad->MergePrimitivesAsPolygon( &polygons );
|
||||
|
||||
if( polygons.OutlineCount() == 0 )
|
||||
break;
|
||||
|
||||
aPad->CustomShapeAsPolygonToBoardPosition( &polygons, shape_pos, aPad->GetOrientation() );
|
||||
m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), &polygons, aPlotMode, &gbr_metadata );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_RECT:
|
||||
default:
|
||||
m_plotter->FlashPadRect( shape_pos, aPad->GetSize(),
|
||||
aPad->GetOrientation(), aPlotMode, &gbr_metadata );
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET polygons;
|
||||
aPad->TransformShapeWithClearanceToPolygon( polygons, 0 );
|
||||
|
||||
if( polygons.OutlineCount() == 0 )
|
||||
break;
|
||||
|
||||
m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), &polygons, aPlotMode,
|
||||
&gbr_metadata );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -617,24 +617,23 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( D_PAD* aPad )
|
|||
wxPoint offset = aPad->GetOffset();
|
||||
|
||||
VECTOR2I c( wx_c.x, wx_c.y );
|
||||
VECTOR2I sz( wx_sz.x, wx_sz.y );
|
||||
|
||||
RotatePoint( &offset, aPad->GetOrientation() );
|
||||
|
||||
solid->SetPos( VECTOR2I( c.x - offset.x, c.y - offset.y ) );
|
||||
solid->SetOffset( VECTOR2I( offset.x, offset.y ) );
|
||||
|
||||
double orient = aPad->GetOrientation() / 10.0;
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
|
||||
if( aPad->GetEffectiveShapes().size() == 1 )
|
||||
{
|
||||
solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
|
||||
solid->SetShape( aPad->GetEffectiveShapes()[0]->Clone() );
|
||||
}
|
||||
else if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
else
|
||||
{
|
||||
// JEY TODO:
|
||||
// TOM TODO: move to SHAPE_COMPOUND...
|
||||
|
||||
SHAPE_POLY_SET outline;
|
||||
outline.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
aPad->CustomShapeAsPolygonToBoardPosition( &outline, wx_c, aPad->GetOrientation() );
|
||||
aPad->TransformShapeWithClearanceToPolygon( outline, 0 );
|
||||
|
||||
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE();
|
||||
|
||||
|
@ -643,138 +642,7 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( D_PAD* aPad )
|
|||
|
||||
solid->SetShape( shape );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( orient == 0.0 || orient == 90.0 || orient == 180.0 || orient == 270.0 )
|
||||
{
|
||||
if( orient == 90.0 || orient == 270.0 )
|
||||
sz = VECTOR2I( sz.y, sz.x );
|
||||
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE_OVAL:
|
||||
if( sz.x == sz.y )
|
||||
solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
|
||||
else
|
||||
{
|
||||
VECTOR2I delta;
|
||||
|
||||
if( sz.x > sz.y )
|
||||
delta = VECTOR2I( ( sz.x - sz.y ) / 2, 0 );
|
||||
else
|
||||
delta = VECTOR2I( 0, ( sz.y - sz.x ) / 2 );
|
||||
|
||||
SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( c - delta, c + delta,
|
||||
std::min( sz.x, sz.y ) );
|
||||
solid->SetShape( shape );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_RECT:
|
||||
solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
{
|
||||
wxPoint coords[4];
|
||||
aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );
|
||||
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE();
|
||||
|
||||
for( int ii = 0; ii < 4; ii++ )
|
||||
{
|
||||
shape->Append( wx_c + coords[ii] );
|
||||
}
|
||||
|
||||
solid->SetShape( shape );
|
||||
break;
|
||||
}
|
||||
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
{
|
||||
SHAPE_POLY_SET outline;
|
||||
aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ) );
|
||||
|
||||
// TransformRoundRectToPolygon creates only one convex polygon
|
||||
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
|
||||
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE();
|
||||
|
||||
for( int ii = 0; ii < poly.PointCount(); ++ii )
|
||||
shape->Append( poly.CPoint( ii ) );
|
||||
|
||||
solid->SetShape( shape );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wxLogTrace( "PNS", "unsupported pad shape" );
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
// PAD_SHAPE_CIRCLE and PAD_SHAPE_CUSTOM already handled above
|
||||
|
||||
case PAD_SHAPE_OVAL:
|
||||
if( sz.x == sz.y )
|
||||
solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
|
||||
else
|
||||
{
|
||||
wxPoint start;
|
||||
wxPoint end;
|
||||
|
||||
int w = aPad->BuildSegmentFromOvalShape( start, end, aPad->GetOrientation(),
|
||||
wxSize( 0, 0 ) );
|
||||
|
||||
SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( start, end, w );
|
||||
shape->Move( aPad->ShapePos() );
|
||||
solid->SetShape( shape );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_RECT:
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
{
|
||||
wxPoint coords[4];
|
||||
aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );
|
||||
|
||||
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE();
|
||||
for( int ii = 0; ii < 4; ii++ )
|
||||
{
|
||||
shape->Append( wx_c + coords[ii] );
|
||||
}
|
||||
|
||||
solid->SetShape( shape );
|
||||
break;
|
||||
}
|
||||
|
||||
case PAD_SHAPE_CHAMFERED_RECT:
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
{
|
||||
SHAPE_POLY_SET outline;
|
||||
aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ) );
|
||||
|
||||
// TransformRoundRectToPolygon creates only one convex polygon
|
||||
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
|
||||
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE();
|
||||
|
||||
for( int ii = 0; ii < poly.PointCount(); ++ii )
|
||||
{
|
||||
shape->Append( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
|
||||
}
|
||||
|
||||
solid->SetShape( shape );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
wxLogTrace( "PNS", "unsupported pad shape" );
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return solid;
|
||||
}
|
||||
|
||||
|
|
|
@ -534,15 +534,17 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
|
|||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
std::vector<wxPoint> polygonal_shape;
|
||||
const SHAPE_POLY_SET& pad_shape = aPad->GetCustomShapeAsPolygon();
|
||||
SHAPE_POLY_SET pad_shape;
|
||||
aPad->MergePrimitivesAsPolygon( &pad_shape );
|
||||
|
||||
#ifdef EXPORT_CUSTOM_PADS_CONVEX_HULL
|
||||
#ifdef EXPORT_CUSTOM_PADS_CONVEX_HULL
|
||||
BuildConvexHull( polygonal_shape, pad_shape );
|
||||
#else
|
||||
#else
|
||||
const SHAPE_LINE_CHAIN& p_outline = pad_shape.COutline( 0 );
|
||||
|
||||
for( int ii = 0; ii < p_outline.PointCount(); ++ii )
|
||||
polygonal_shape.push_back( wxPoint( p_outline.CPoint( ii ) ) );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The polygon must be closed
|
||||
if( polygonal_shape.front() != polygonal_shape.back() )
|
||||
|
|
|
@ -596,13 +596,14 @@ int FOOTPRINT_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
pad->SetPosition( wxPoint( anchor->x, anchor->y ) );
|
||||
pad->Rotate( wxPoint( anchor->x, anchor->y ), deltaAngle );
|
||||
pad->AddPrimitives( shapes );
|
||||
pad->ClearFlags();
|
||||
|
||||
bool result = pad->MergePrimitivesAsPolygon();
|
||||
pad->Rotate( wxPoint( anchor->x, anchor->y ), deltaAngle );
|
||||
SHAPE_POLY_SET mergedPolygon;
|
||||
pad->MergePrimitivesAsPolygon( &mergedPolygon );
|
||||
|
||||
if( !result )
|
||||
if( mergedPolygon.OutlineCount() > 1 )
|
||||
{
|
||||
DisplayErrorMessage( m_frame, _( "Cannot convert items to a custom-shaped pad:\n"
|
||||
"selected items do not form a single solid shape.") );
|
||||
|
|
|
@ -391,18 +391,14 @@ void ZONE_FILLER::addKnockout( D_PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles )
|
|||
{
|
||||
if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
// the pad shape in zone can be its convex hull or the shape itself
|
||||
SHAPE_POLY_SET outline( aPad->GetCustomShapeAsPolygon() );
|
||||
int numSegs = std::max( GetArcToSegmentCount( aGap, m_high_def, 360.0 ), 6 );
|
||||
double correction = GetCircletoPolyCorrectionFactor( numSegs );
|
||||
outline.Inflate( KiROUND( aGap * correction ), numSegs );
|
||||
aPad->CustomShapeAsPolygonToBoardPosition( &outline, aPad->GetPosition(),
|
||||
aPad->GetOrientation() );
|
||||
SHAPE_POLY_SET poly;
|
||||
aPad->TransformShapeWithClearanceToPolygon( poly, aGap, m_high_def );
|
||||
|
||||
// the pad shape in zone can be its convex hull or the shape itself
|
||||
if( aPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||
{
|
||||
std::vector<wxPoint> convex_hull;
|
||||
BuildConvexHull( convex_hull, outline );
|
||||
BuildConvexHull( convex_hull, poly );
|
||||
|
||||
aHoles.NewOutline();
|
||||
|
||||
|
@ -410,7 +406,7 @@ void ZONE_FILLER::addKnockout( D_PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles )
|
|||
aHoles.Append( pt );
|
||||
}
|
||||
else
|
||||
aHoles.Append( outline );
|
||||
aHoles.Append( poly );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue