kicad/3d-viewer/3d_canvas/create_layer_poly.cpp

245 lines
9.0 KiB
C++

/*
* 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-2016 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @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
*/
#include "cinfo3d_visu.h"
#include <convert_basic_shapes_to_polygon.h>
#include <class_edge_mod.h>
#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 CINFO3D_VISU::buildPadShapePolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
wxSize aInflateValue,
int aSegmentsPerCircle,
double aCorrectionFactor ) const
{
wxPoint corners[4];
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,
aSegmentsPerCircle, aCorrectionFactor );
}
break;
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_RECT:
{
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
polyList.Append( aPad->GetCustomShapeAsPolygon() );
aPad->CustomShapeAsPolygonToBoardPosition( &polyList, aPad->ShapePos(), aPad->GetOrientation() );
aCornerBuffer.Append( polyList );
}
break;
}
}
void CINFO3D_VISU::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
int aWidth ) const
{
if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
{
unsigned int nr_sides_per_circle = GetNrSegmentsCircle( ( aPad->GetSize().x / 2 +
aWidth / 2 ) * 2 );
TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(),
aPad->GetSize().x / 2, nr_sides_per_circle, aWidth );
return;
}
// For other shapes, draw polygon outlines
SHAPE_POLY_SET corners;
unsigned int nr_sides_per_circle = GetNrSegmentsCircle( glm::min( aPad->GetSize().x,
aPad->GetSize().y) );
buildPadShapePolygon( aPad, corners, wxSize( 0, 0 ),
nr_sides_per_circle,
GetCircleCorrectionFactor( nr_sides_per_circle ) );
// Add outlines as thick segments in polygon buffer
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
for( int ii = 0; ii < path.PointCount(); ++ii )
{
const VECTOR2I& a = path.CPoint( ii );
const VECTOR2I& b = path.CPoint( ii + 1 );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
wxPoint( a.x, a.y ),
wxPoint( b.x, b.y ),
nr_sides_per_circle,
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 CINFO3D_VISU::transformPadsShapesWithClearanceToPolygon( const DLIST<D_PAD>& aPads, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue,
bool aSkipNPTHPadsWihNoCopper ) const
{
const D_PAD* pad = aPads;
wxSize margin;
for( ; pad != NULL; pad = pad->Next() )
{
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;
}
unsigned int aCircleToSegmentsCount = GetNrSegmentsCircle( pad->GetSize().x );
double aCorrectionFactor = GetCircleCorrectionFactor( aCircleToSegmentsCount );
buildPadShapePolygon( pad, aCornerBuffer, margin,
aCircleToSegmentsCount, aCorrectionFactor );
}
}
void CINFO3D_VISU::transformGraphicModuleEdgeToPolygonSet( const MODULE *aModule,
PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer ) const
{
for( const EDA_ITEM* item = aModule->GraphicalItemsList();
item != NULL;
item = item->Next() )
{
switch( item->Type() )
{
case PCB_MODULE_EDGE_T:
{
EDGE_MODULE*outline = (EDGE_MODULE*) item;
if( outline->GetLayer() != aLayer )
break;
unsigned int aCircleToSegmentsCount =
GetNrSegmentsCircle( outline->GetBoundingBox().GetSizeMax() );
double aCorrectionFactor = GetCircleCorrectionFactor( aCircleToSegmentsCount );
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer,
0,
aCircleToSegmentsCount,
aCorrectionFactor );
}
break;
default:
break;
}
}
}