summaryrefslogtreecommitdiff
path: root/pcbnew/pcb_painter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pcbnew/pcb_painter.cpp')
-rw-r--r--pcbnew/pcb_painter.cpp1026
1 files changed, 1026 insertions, 0 deletions
diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp
new file mode 100644
index 0000000..07dcd11
--- /dev/null
+++ b/pcbnew/pcb_painter.cpp
@@ -0,0 +1,1026 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013-2016 CERN
+ * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
+ * @author Maciej Suminski <maciej.suminski@cern.ch>
+ *
+ * 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
+ */
+
+#include <class_board.h>
+#include <class_track.h>
+#include <class_module.h>
+#include <class_pad.h>
+#include <class_drawsegment.h>
+#include <class_zone.h>
+#include <class_pcb_text.h>
+#include <class_colors_design_settings.h>
+#include <class_marker_pcb.h>
+#include <class_dimension.h>
+#include <class_mire.h>
+#include <class_marker_pcb.h>
+
+#include <pcb_painter.h>
+#include <gal/graphics_abstraction_layer.h>
+
+using namespace KIGFX;
+
+PCB_RENDER_SETTINGS::PCB_RENDER_SETTINGS()
+{
+ m_backgroundColor = COLOR4D( 0.0, 0.0, 0.0, 1.0 );
+ m_padNumbers = true;
+ m_netNamesOnPads = true;
+ m_netNamesOnTracks = true;
+ m_displayZoneMode = DZ_SHOW_FILLED;
+
+ // By default everything should be displayed as filled
+ for( unsigned int i = 0; i < TOTAL_LAYER_COUNT; ++i )
+ {
+ m_sketchMode[i] = false;
+ }
+
+ update();
+}
+
+
+void PCB_RENDER_SETTINGS::ImportLegacyColors( const COLORS_DESIGN_SETTINGS* aSettings )
+{
+ for( int i = 0; i < LAYER_ID_COUNT; i++ )
+ {
+ m_layerColors[i] = m_legacyColorMap[aSettings->GetLayerColor( i )];
+ }
+
+ for( int i = 0; i < END_PCB_VISIBLE_LIST; i++ )
+ {
+ m_layerColors[ITEM_GAL_LAYER( i )] = m_legacyColorMap[aSettings->GetItemColor( i )];
+ }
+
+ m_layerColors[ITEM_GAL_LAYER( MOD_TEXT_FR_VISIBLE )] = m_layerColors[F_SilkS];
+ m_layerColors[ITEM_GAL_LAYER( MOD_TEXT_BK_VISIBLE )] = m_layerColors[B_SilkS];
+
+ // Default colors for specific layers
+ m_layerColors[ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE )] = COLOR4D( 0.5, 0.4, 0.0, 0.8 );
+ m_layerColors[ITEM_GAL_LAYER( PADS_HOLES_VISIBLE )] = COLOR4D( 0.0, 0.5, 0.5, 0.8 );
+ m_layerColors[ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE )] = COLOR4D( 0.6, 0.6, 0.6, 0.8 );
+ m_layerColors[ITEM_GAL_LAYER( VIA_BBLIND_VISIBLE )] = COLOR4D( 0.6, 0.6, 0.6, 0.8 );
+ m_layerColors[ITEM_GAL_LAYER( VIA_MICROVIA_VISIBLE )] = COLOR4D( 0.4, 0.4, 0.8, 0.8 );
+ m_layerColors[ITEM_GAL_LAYER( PADS_VISIBLE )] = COLOR4D( 0.6, 0.6, 0.6, 0.8 );
+ m_layerColors[NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE )] = COLOR4D( 1.0, 1.0, 1.0, 0.9 );
+ m_layerColors[NETNAMES_GAL_LAYER( PAD_FR_NETNAMES_VISIBLE )] = COLOR4D( 1.0, 1.0, 1.0, 0.9 );
+ m_layerColors[NETNAMES_GAL_LAYER( PAD_BK_NETNAMES_VISIBLE )] = COLOR4D( 1.0, 1.0, 1.0, 0.9 );
+ m_layerColors[ITEM_GAL_LAYER( ANCHOR_VISIBLE )] = COLOR4D( 0.3, 0.3, 1.0, 0.9 );
+ m_layerColors[ITEM_GAL_LAYER( RATSNEST_VISIBLE )] = COLOR4D( 0.4, 0.4, 0.4, 0.8 );
+ m_layerColors[ITEM_GAL_LAYER( WORKSHEET )] = COLOR4D( 0.5, 0.0, 0.0, 0.8 );
+ m_layerColors[ITEM_GAL_LAYER( DRC_VISIBLE )] = COLOR4D( 1.0, 0.0, 0.0, 0.8 );
+
+ // Netnames for copper layers
+ for( LSEQ cu = LSET::AllCuMask().CuStack(); cu; ++cu )
+ {
+ LAYER_ID layer = *cu;
+
+ m_layerColors[GetNetnameLayer( layer )] = COLOR4D( 0.8, 0.8, 0.8, 0.7 );
+ }
+
+ update();
+}
+
+
+void PCB_RENDER_SETTINGS::LoadDisplayOptions( const DISPLAY_OPTIONS* aOptions )
+{
+ if( aOptions == NULL )
+ return;
+
+ m_hiContrastEnabled = aOptions->m_ContrastModeDisplay;
+ m_padNumbers = aOptions->m_DisplayPadNum;
+
+ // Whether to draw tracks, vias & pads filled or as outlines
+ m_sketchMode[ITEM_GAL_LAYER( PADS_VISIBLE )] = !aOptions->m_DisplayPadFill;
+ m_sketchMode[ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE )] = !aOptions->m_DisplayViaFill;
+ m_sketchMode[ITEM_GAL_LAYER( VIA_BBLIND_VISIBLE )] = !aOptions->m_DisplayViaFill;
+ m_sketchMode[ITEM_GAL_LAYER( VIA_MICROVIA_VISIBLE )] = !aOptions->m_DisplayViaFill;
+ m_sketchMode[ITEM_GAL_LAYER( TRACKS_VISIBLE )] = !aOptions->m_DisplayPcbTrackFill;
+
+ switch( aOptions->m_DisplayNetNamesMode )
+ {
+ case 0:
+ m_netNamesOnPads = false;
+ m_netNamesOnTracks = false;
+ break;
+
+ case 1:
+ m_netNamesOnPads = true;
+ m_netNamesOnTracks = false;
+ break;
+
+ case 2:
+ m_netNamesOnPads = false;
+ m_netNamesOnTracks = true;
+ break;
+
+ case 3:
+ m_netNamesOnPads = true;
+ m_netNamesOnTracks = true;
+ break;
+ }
+
+ switch( aOptions->m_DisplayZonesMode )
+ {
+ case 0:
+ m_displayZoneMode = DZ_SHOW_FILLED;
+ break;
+
+ case 1:
+ m_displayZoneMode = DZ_HIDE_FILLED;
+ break;
+
+ case 2:
+ m_displayZoneMode = DZ_SHOW_OUTLINED;
+ break;
+ }
+}
+
+
+const COLOR4D& PCB_RENDER_SETTINGS::GetColor( const VIEW_ITEM* aItem, int aLayer ) const
+{
+ int netCode = -1;
+ const EDA_ITEM* item = static_cast<const EDA_ITEM*>( aItem );
+
+ if( item )
+ {
+ if( item->IsSelected() )
+ {
+ return m_layerColorsSel[aLayer];
+ }
+
+ // Try to obtain the netcode for the item
+ if( const BOARD_CONNECTED_ITEM* conItem = dyn_cast<const BOARD_CONNECTED_ITEM*> ( item ) )
+ netCode = conItem->GetNetCode();
+ }
+
+ // Single net highlight mode
+ if( m_highlightEnabled && netCode == m_highlightNetcode )
+ return m_layerColorsHi[aLayer];
+
+ // Return grayish color for non-highlighted layers in the high contrast mode
+ if( m_hiContrastEnabled && m_activeLayers.count( aLayer ) == 0 )
+ return m_hiContrastColor;
+
+ // Catch the case when highlight and high-contraste modes are enabled
+ // and we are drawing a not highlighted track
+ if( m_highlightEnabled )
+ return m_layerColorsDark[aLayer];
+
+ // No special modificators enabled
+ return m_layerColors[aLayer];
+}
+
+
+void PCB_RENDER_SETTINGS::update()
+{
+ RENDER_SETTINGS::update();
+
+ // Calculate darkened/highlighted variants of layer colors
+ for( int i = 0; i < TOTAL_LAYER_COUNT; i++ )
+ {
+ m_layerColorsHi[i] = m_layerColors[i].Brightened( m_highlightFactor );
+ m_layerColorsDark[i] = m_layerColors[i].Darkened( 1.0 - m_highlightFactor );
+ m_layerColorsSel[i] = m_layerColors[i].Brightened( m_selectFactor );
+ }
+}
+
+
+PCB_PAINTER::PCB_PAINTER( GAL* aGal ) :
+ PAINTER( aGal )
+{
+}
+
+
+bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
+{
+ const EDA_ITEM* item = static_cast<const EDA_ITEM*>( aItem );
+
+ // the "cast" applied in here clarifies which overloaded draw() is called
+ switch( item->Type() )
+ {
+ case PCB_ZONE_T:
+ case PCB_TRACE_T:
+ draw( static_cast<const TRACK*>( item ), aLayer );
+ break;
+
+ case PCB_VIA_T:
+ draw( static_cast<const VIA*>( item ), aLayer );
+ break;
+
+ case PCB_PAD_T:
+ draw( static_cast<const D_PAD*>( item ), aLayer );
+ break;
+
+ case PCB_LINE_T:
+ case PCB_MODULE_EDGE_T:
+ draw( static_cast<const DRAWSEGMENT*>( item ), aLayer );
+ break;
+
+ case PCB_TEXT_T:
+ draw( static_cast<const TEXTE_PCB*>( item ), aLayer );
+ break;
+
+ case PCB_MODULE_TEXT_T:
+ draw( static_cast<const TEXTE_MODULE*>( item ), aLayer );
+ break;
+
+ case PCB_MODULE_T:
+ draw( static_cast<const MODULE*>( item ), aLayer );
+ break;
+
+ case PCB_ZONE_AREA_T:
+ draw( static_cast<const ZONE_CONTAINER*>( item ) );
+ break;
+
+ case PCB_DIMENSION_T:
+ draw( static_cast<const DIMENSION*>( item ), aLayer );
+ break;
+
+ case PCB_TARGET_T:
+ draw( static_cast<const PCB_TARGET*>( item ) );
+ break;
+
+ case PCB_MARKER_T:
+ draw( static_cast<const MARKER_PCB*>( item ) );
+ break;
+
+ default:
+ // Painter does not know how to draw the object
+ return false;
+ }
+
+ return true;
+}
+
+
+void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer )
+{
+ VECTOR2D start( aTrack->GetStart() );
+ VECTOR2D end( aTrack->GetEnd() );
+ int width = aTrack->GetWidth();
+
+ if( m_pcbSettings.m_netNamesOnTracks && IsNetnameLayer( aLayer ) )
+ {
+ // If there is a net name - display it on the track
+ if( aTrack->GetNetCode() > NETINFO_LIST::UNCONNECTED )
+ {
+ VECTOR2D line = ( end - start );
+ double length = line.EuclideanNorm();
+
+ // Check if the track is long enough to have a netname displayed
+ if( length < 10 * width )
+ return;
+
+ const wxString& netName = aTrack->GetShortNetname();
+ VECTOR2D textPosition = start + line / 2.0; // center of the track
+ double textOrientation = -atan( line.y / line.x );
+ double textSize = std::min( static_cast<double>( width ), length / netName.length() );
+
+ // Set a proper color for the label
+ const COLOR4D& color = m_pcbSettings.GetColor( aTrack, aTrack->GetLayer() );
+ const COLOR4D labelColor = m_pcbSettings.GetColor( NULL, aLayer );
+
+ if( color.GetBrightness() > 0.5 )
+ m_gal->SetStrokeColor( labelColor.Inverted() );
+ else
+ m_gal->SetStrokeColor( labelColor );
+
+ m_gal->SetLineWidth( width / 10.0 );
+ m_gal->SetBold( false );
+ m_gal->SetItalic( false );
+ m_gal->SetMirrored( false );
+ m_gal->SetGlyphSize( VECTOR2D( textSize * 0.7, textSize * 0.7 ) );
+ m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
+ m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
+ m_gal->StrokeText( netName, textPosition, textOrientation );
+ }
+ }
+ else if( IsCopperLayer( aLayer ) )
+ {
+ // Draw a regular track
+ const COLOR4D& color = m_pcbSettings.GetColor( aTrack, aLayer );
+ m_gal->SetStrokeColor( color );
+ m_gal->SetIsStroke( true );
+
+ if( m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( TRACKS_VISIBLE )] )
+ {
+ // Outline mode
+ m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
+ m_gal->SetIsFill( false );
+ }
+ else
+ {
+ // Filled mode
+ m_gal->SetFillColor( color );
+ m_gal->SetIsFill( true );
+ }
+
+ m_gal->DrawSegment( start, end, width );
+ }
+}
+
+
+void PCB_PAINTER::draw( const VIA* aVia, int aLayer )
+{
+ VECTOR2D center( aVia->GetStart() );
+ double radius = 0.0;
+
+ // Only draw the via if at least one of the layers it crosses is being displayed
+ BOARD* brd = aVia->GetBoard( );
+ if( !( brd->GetVisibleLayers() & aVia->GetLayerSet() ).any() )
+ return;
+
+ // Choose drawing settings depending on if we are drawing via's pad or hole
+ if( aLayer == ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ) )
+ radius = aVia->GetDrillValue() / 2.0;
+ else
+ radius = aVia->GetWidth() / 2.0;
+
+ bool sketchMode = false;
+ const COLOR4D& color = m_pcbSettings.GetColor( aVia, aLayer );
+
+ switch( aVia->GetViaType() )
+ {
+ case VIA_THROUGH:
+ sketchMode = m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE )];
+ break;
+
+ case VIA_BLIND_BURIED:
+ sketchMode = m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( VIA_BBLIND_VISIBLE )];
+ break;
+
+ case VIA_MICROVIA:
+ sketchMode = m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( VIA_MICROVIA_VISIBLE )];
+ break;
+
+ default:
+ assert( false );
+ break;
+ }
+
+ if( aVia->GetViaType() == VIA_BLIND_BURIED )
+ {
+ LAYER_ID layerTop, layerBottom;
+ aVia->LayerPair( &layerTop, &layerBottom );
+
+ if( aLayer == ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ) )
+ { // TODO outline mode
+ m_gal->SetIsFill( true );
+ m_gal->SetIsStroke( false );
+ m_gal->SetFillColor( color );
+ m_gal->DrawCircle( center, radius );
+ }
+ else
+ {
+ double width = ( aVia->GetWidth() - aVia->GetDrillValue() ) / 2.0;
+
+ m_gal->SetLineWidth( width );
+ m_gal->SetIsFill( true );
+ m_gal->SetIsStroke( false );
+ m_gal->SetFillColor( color );
+
+ if( aLayer == layerTop )
+ {
+ m_gal->DrawArc( center, radius, 0.0, M_PI / 2.0 );
+ }
+ else if( aLayer == layerBottom )
+ {
+ m_gal->DrawArc( center, radius, M_PI, 3.0 * M_PI / 2.0 );
+ }
+ else if( aLayer == ITEM_GAL_LAYER( VIA_BBLIND_VISIBLE ) )
+ {
+ m_gal->DrawArc( center, radius, M_PI / 2.0, M_PI );
+ m_gal->DrawArc( center, radius, 3.0 * M_PI / 2.0, 2.0 * M_PI );
+ }
+ }
+ }
+ else
+ {
+ m_gal->SetIsFill( !sketchMode );
+ m_gal->SetIsStroke( sketchMode );
+
+ if( sketchMode )
+ {
+ // Outline mode
+ m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
+ m_gal->SetStrokeColor( color );
+ }
+ else
+ {
+ // Filled mode
+ m_gal->SetFillColor( color );
+ }
+
+ m_gal->DrawCircle( center, radius );
+ }
+}
+
+
+void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
+{
+ VECTOR2D size;
+ VECTOR2D position( aPad->GetPosition() );
+ PAD_SHAPE_T shape;
+ double m, n;
+ double orientation = aPad->GetOrientation();
+ wxString buffer;
+
+ // Draw description layer
+ if( IsNetnameLayer( aLayer ) )
+ {
+ // Is anything that we can display enabled?
+ if( m_pcbSettings.m_netNamesOnPads || m_pcbSettings.m_padNumbers )
+ {
+ // Min char count to calculate string size
+ const int MIN_CHAR_COUNT = 3;
+
+ bool displayNetname = ( m_pcbSettings.m_netNamesOnPads &&
+ !aPad->GetNetname().empty() );
+ VECTOR2D padsize = VECTOR2D( aPad->GetSize() );
+ double maxSize = PCB_RENDER_SETTINGS::MAX_FONT_SIZE;
+ double size = padsize.y;
+
+ // Keep the size ratio for the font, but make it smaller
+ if( padsize.x < padsize.y )
+ {
+ orientation += 900.0;
+ size = padsize.x;
+ std::swap( padsize.x, padsize.y );
+ }
+ else if( padsize.x == padsize.y )
+ {
+ // If the text is displayed on a symmetrical pad, do not rotate it
+ orientation = 0.0;
+ }
+
+ // Font size limits
+ if( size > maxSize )
+ size = maxSize;
+
+ m_gal->Save();
+ m_gal->Translate( position );
+
+ // do not display descriptions upside down
+ NORMALIZE_ANGLE_90( orientation );
+ m_gal->Rotate( -orientation * M_PI / 1800.0 );
+
+ // Default font settings
+ m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
+ m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
+ m_gal->SetBold( false );
+ m_gal->SetItalic( false );
+ m_gal->SetMirrored( false );
+
+ // Set a proper color for the label
+ const COLOR4D& color = m_pcbSettings.GetColor( aPad, aPad->GetLayer() );
+ const COLOR4D labelColor = m_pcbSettings.GetColor( NULL, aLayer );
+
+ if( color.GetBrightness() > 0.5 )
+ m_gal->SetStrokeColor( labelColor.Inverted() );
+ else
+ m_gal->SetStrokeColor( labelColor );
+
+ VECTOR2D textpos( 0.0, 0.0);
+
+ // Divide the space, to display both pad numbers and netnames
+ // and set the Y text position to display 2 lines
+ if( displayNetname && m_pcbSettings.m_padNumbers )
+ {
+ size = size / 2.0;
+ textpos.y = size / 2.0;
+ }
+
+ if( displayNetname )
+ {
+ // calculate the size of net name text:
+ double tsize = padsize.x / aPad->GetShortNetname().Length();
+ tsize = std::min( tsize, size );
+ // Use a smaller text size to handle interline, pen size..
+ tsize *= 0.7;
+ VECTOR2D namesize( tsize, tsize );
+ m_gal->SetGlyphSize( namesize );
+ m_gal->SetLineWidth( namesize.x / 12.0 );
+ m_gal->StrokeText( aPad->GetShortNetname(), textpos, 0.0 );
+ }
+
+ if( m_pcbSettings.m_padNumbers )
+ {
+ textpos.y = -textpos.y;
+ aPad->StringPadName( buffer );
+ int len = buffer.Length();
+ double tsize = padsize.x / std::max( len, MIN_CHAR_COUNT );
+ tsize = std::min( tsize, size );
+ // Use a smaller text size to handle interline, pen size..
+ tsize *= 0.7;
+ tsize = std::min( tsize, size );
+ VECTOR2D numsize( tsize, tsize );
+
+ m_gal->SetGlyphSize( numsize );
+ m_gal->SetLineWidth( numsize.x / 12.0 );
+ m_gal->StrokeText( aPad->GetPadName(), textpos, 0.0 );
+ }
+
+ m_gal->Restore();
+ }
+ return;
+ }
+
+ // Pad drawing
+ const COLOR4D& color = m_pcbSettings.GetColor( aPad, aLayer );
+ if( m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( PADS_VISIBLE )] )
+ {
+ // Outline mode
+ m_gal->SetIsFill( false );
+ m_gal->SetIsStroke( true );
+ m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
+ m_gal->SetStrokeColor( color );
+ }
+ else
+ {
+ // Filled mode
+ m_gal->SetIsFill( true );
+ m_gal->SetIsStroke( false );
+ m_gal->SetFillColor( color );
+ }
+
+ m_gal->Save();
+ m_gal->Translate( VECTOR2D( aPad->GetPosition() ) );
+ m_gal->Rotate( -aPad->GetOrientation() * M_PI / 1800.0 );
+
+ // Choose drawing settings depending on if we are drawing a pad itself or a hole
+ if( aLayer == ITEM_GAL_LAYER( PADS_HOLES_VISIBLE ) )
+ {
+ // Drawing hole: has same shape as PAD_CIRCLE or PAD_OVAL
+ size = VECTOR2D( aPad->GetDrillSize() ) / 2.0;
+ shape = aPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ? PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE;
+ }
+ else if( aLayer == F_Mask || aLayer == B_Mask )
+ {
+ // Drawing soldermask
+ int soldermaskMargin = aPad->GetSolderMaskMargin();
+
+ m_gal->Translate( VECTOR2D( aPad->GetOffset() ) );
+ size = VECTOR2D( aPad->GetSize().x / 2.0 + soldermaskMargin,
+ aPad->GetSize().y / 2.0 + soldermaskMargin );
+ shape = aPad->GetShape();
+ }
+ else if( aLayer == F_Paste || aLayer == B_Paste )
+ {
+ // Drawing solderpaste
+ wxSize solderpasteMargin = aPad->GetSolderPasteMargin();
+
+ m_gal->Translate( VECTOR2D( aPad->GetOffset() ) );
+ size = VECTOR2D( aPad->GetSize().x / 2.0 + solderpasteMargin.x,
+ aPad->GetSize().y / 2.0 + solderpasteMargin.y );
+ shape = aPad->GetShape();
+ }
+ else
+ {
+ // Drawing every kind of pad
+ m_gal->Translate( VECTOR2D( aPad->GetOffset() ) );
+ size = VECTOR2D( aPad->GetSize() ) / 2.0;
+ shape = aPad->GetShape();
+ }
+
+ switch( shape )
+ {
+ case PAD_SHAPE_OVAL:
+ if( size.y >= size.x )
+ {
+ m = ( size.y - size.x );
+ n = size.x;
+
+ if( m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( PADS_VISIBLE )] )
+ {
+ // Outline mode
+ m_gal->DrawArc( VECTOR2D( 0, -m ), n, -M_PI, 0 );
+ m_gal->DrawArc( VECTOR2D( 0, m ), n, M_PI, 0 );
+ m_gal->DrawLine( VECTOR2D( -n, -m ), VECTOR2D( -n, m ) );
+ m_gal->DrawLine( VECTOR2D( n, -m ), VECTOR2D( n, m ) );
+ }
+ else
+ {
+ // Filled mode
+ m_gal->DrawCircle( VECTOR2D( 0, -m ), n );
+ m_gal->DrawCircle( VECTOR2D( 0, m ), n );
+ m_gal->DrawRectangle( VECTOR2D( -n, -m ), VECTOR2D( n, m ) );
+ }
+ }
+ else
+ {
+ m = ( size.x - size.y );
+ n = size.y;
+
+ if( m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( PADS_VISIBLE )] )
+ {
+ // Outline mode
+ 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 );
+ m_gal->DrawLine( VECTOR2D( -m, -n ), VECTOR2D( m, -n ) );
+ m_gal->DrawLine( VECTOR2D( -m, n ), VECTOR2D( m, n ) );
+ }
+ else
+ {
+ // Filled mode
+ m_gal->DrawCircle( VECTOR2D( -m, 0 ), n );
+ m_gal->DrawCircle( VECTOR2D( m, 0 ), n );
+ m_gal->DrawRectangle( VECTOR2D( -m, -n ), VECTOR2D( m, n ) );
+ }
+ }
+ break;
+
+ case PAD_SHAPE_RECT:
+ m_gal->DrawRectangle( VECTOR2D( -size.x, -size.y ), VECTOR2D( size.x, size.y ) );
+ break;
+
+ case PAD_SHAPE_TRAPEZOID:
+ {
+ std::deque<VECTOR2D> pointList;
+ wxPoint corners[4];
+
+ VECTOR2D padSize = VECTOR2D( aPad->GetSize().x, aPad->GetSize().y ) / 2;
+ VECTOR2D deltaPadSize = size - padSize; // = solder[Paste/Mask]Margin or 0
+
+ aPad->BuildPadPolygon( corners, wxSize( deltaPadSize.x, deltaPadSize.y ), 0.0 );
+ pointList.push_back( VECTOR2D( corners[0] ) );
+ pointList.push_back( VECTOR2D( corners[1] ) );
+ pointList.push_back( VECTOR2D( corners[2] ) );
+ pointList.push_back( VECTOR2D( corners[3] ) );
+
+ if( m_pcbSettings.m_sketchMode[PADS_VISIBLE] )
+ {
+ // Add the beginning point to close the outline
+ pointList.push_back( pointList.front() );
+ m_gal->DrawPolyline( pointList );
+ }
+ else
+ {
+ m_gal->DrawPolygon( pointList );
+ }
+ }
+ break;
+
+ case PAD_SHAPE_CIRCLE:
+ m_gal->DrawCircle( VECTOR2D( 0.0, 0.0 ), size.x );
+ break;
+ }
+
+ m_gal->Restore();
+}
+
+
+void PCB_PAINTER::draw( const DRAWSEGMENT* aSegment, int aLayer )
+{
+ const COLOR4D& color = m_pcbSettings.GetColor( aSegment, aSegment->GetLayer() );
+
+ m_gal->SetIsFill( false );
+ m_gal->SetIsStroke( true );
+ m_gal->SetStrokeColor( color );
+
+ if( m_pcbSettings.m_sketchMode[aLayer] )
+ m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth ); // Outline mode
+ else
+ m_gal->SetLineWidth( aSegment->GetWidth() ); // Filled mode
+
+ switch( aSegment->GetShape() )
+ {
+ case S_SEGMENT:
+ m_gal->DrawLine( VECTOR2D( aSegment->GetStart() ), VECTOR2D( aSegment->GetEnd() ) );
+ break;
+
+ case S_RECT:
+ wxASSERT_MSG( false, wxT( "Not tested yet" ) );
+ m_gal->DrawRectangle( VECTOR2D( aSegment->GetStart() ), VECTOR2D( aSegment->GetEnd() ) );
+ break;
+
+ case S_ARC:
+ m_gal->DrawArc( VECTOR2D( aSegment->GetCenter() ), aSegment->GetRadius(),
+ aSegment->GetArcAngleStart() * M_PI / 1800.0,
+ ( aSegment->GetArcAngleStart() + aSegment->GetAngle() ) * M_PI / 1800.0 );
+ break;
+
+ case S_CIRCLE:
+ m_gal->DrawCircle( VECTOR2D( aSegment->GetCenter() ), aSegment->GetRadius() );
+ break;
+
+ case S_POLYGON:
+ {
+ std::deque<VECTOR2D> pointsList;
+
+ m_gal->SetIsFill( true );
+ m_gal->SetIsStroke( false );
+ m_gal->SetFillColor( color );
+
+ m_gal->Save();
+
+ MODULE* module = aSegment->GetParentModule();
+ if( module )
+ {
+ m_gal->Translate( module->GetPosition() );
+ m_gal->Rotate( -module->GetOrientation() * M_PI / 1800.0 );
+ }
+ else
+ {
+ // not tested
+ m_gal->Translate( aSegment->GetPosition() );
+ m_gal->Rotate( -aSegment->GetAngle() * M_PI / 1800.0 );
+ }
+
+ std::copy( aSegment->GetPolyPoints().begin(), aSegment->GetPolyPoints().end(),
+ std::back_inserter( pointsList ) );
+
+ m_gal->SetLineWidth( aSegment->GetWidth() );
+ m_gal->DrawPolyline( pointsList );
+ m_gal->DrawPolygon( pointsList );
+
+ m_gal->Restore();
+ break;
+ }
+
+ case S_CURVE:
+ m_gal->DrawCurve( VECTOR2D( aSegment->GetStart() ),
+ VECTOR2D( aSegment->GetBezControl1() ),
+ VECTOR2D( aSegment->GetBezControl2() ),
+ VECTOR2D( aSegment->GetEnd() ) );
+ break;
+
+ case S_LAST:
+ break;
+ }
+}
+
+
+void PCB_PAINTER::draw( const TEXTE_PCB* aText, int aLayer )
+{
+ wxString shownText( aText->GetShownText() );
+ if( shownText.Length() == 0 )
+ return;
+
+ const COLOR4D& color = m_pcbSettings.GetColor( aText, aText->GetLayer() );
+ VECTOR2D position( aText->GetTextPosition().x, aText->GetTextPosition().y );
+ double orientation = aText->GetOrientation() * M_PI / 1800.0;
+
+ if( m_pcbSettings.m_sketchMode[aLayer] )
+ {
+ // Outline mode
+ m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
+ }
+ else
+ {
+ // Filled mode
+ m_gal->SetLineWidth( aText->GetThickness() );
+ }
+
+ m_gal->SetIsFill( false );
+ m_gal->SetIsStroke( true );
+ m_gal->SetStrokeColor( color );
+ m_gal->SetTextAttributes( aText );
+ m_gal->StrokeText( shownText, position, orientation );
+}
+
+
+void PCB_PAINTER::draw( const TEXTE_MODULE* aText, int aLayer )
+{
+ wxString shownText( aText->GetShownText() );
+ if( shownText.Length() == 0 )
+ return;
+
+ const COLOR4D& color = m_pcbSettings.GetColor( aText, aLayer );
+ VECTOR2D position( aText->GetTextPosition().x, aText->GetTextPosition().y );
+ double orientation = aText->GetDrawRotation() * M_PI / 1800.0;
+
+ if( m_pcbSettings.m_sketchMode[aLayer] )
+ {
+ // Outline mode
+ m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
+ }
+ else
+ {
+ // Filled mode
+ m_gal->SetLineWidth( aText->GetThickness() );
+ }
+
+ m_gal->SetIsFill( false );
+ m_gal->SetIsStroke( true );
+ m_gal->SetStrokeColor( color );
+ m_gal->SetTextAttributes( aText );
+ m_gal->StrokeText( shownText, position, orientation );
+
+ // Draw the umbilical line
+ if( aText->IsSelected() && aText->GetType() != TEXTE_MODULE::TEXT_is_DIVERS )
+ {
+ m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
+ m_gal->SetStrokeColor( COLOR4D( 0.0, 0.0, 1.0, 1.0 ) );
+ m_gal->DrawLine( position, aText->GetParent()->GetPosition() );
+ }
+}
+
+
+void PCB_PAINTER::draw( const MODULE* aModule, int aLayer )
+{
+ if( aLayer == ITEM_GAL_LAYER( ANCHOR_VISIBLE ) )
+ {
+ const COLOR4D color = m_pcbSettings.GetColor( aModule, ITEM_GAL_LAYER( ANCHOR_VISIBLE ) );
+
+ // Draw anchor
+ m_gal->SetStrokeColor( color );
+ m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
+
+ // Keep the size constant, not related to the scale
+ double anchorSize = 5.0 / m_gal->GetWorldScale();
+
+ VECTOR2D center = aModule->GetPosition();
+ m_gal->DrawLine( center - VECTOR2D( anchorSize, 0 ), center + VECTOR2D( anchorSize, 0 ) );
+ m_gal->DrawLine( center - VECTOR2D( 0, anchorSize ), center + VECTOR2D( 0, anchorSize ) );
+ }
+}
+
+
+void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone )
+{
+ const COLOR4D& color = m_pcbSettings.GetColor( aZone, aZone->GetLayer() );
+ std::deque<VECTOR2D> corners;
+ PCB_RENDER_SETTINGS::DisplayZonesMode displayMode = m_pcbSettings.m_displayZoneMode;
+
+ // Draw the outline
+ m_gal->SetStrokeColor( color );
+ m_gal->SetIsFill( false );
+ m_gal->SetIsStroke( true );
+ m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
+
+ const CPolyLine* outline = aZone->Outline();
+ for( int i = 0; i < outline->GetCornersCount(); ++i )
+ {
+ corners.push_back( VECTOR2D( outline->GetPos( i ) ) );
+
+ if( outline->IsEndContour( i ) )
+ {
+ // The last point for closing the polyline
+ corners.push_back( corners[0] );
+ m_gal->DrawPolyline( corners );
+ corners.clear();
+ }
+ }
+
+ // Draw the filling
+ if( displayMode != PCB_RENDER_SETTINGS::DZ_HIDE_FILLED )
+ {
+ const SHAPE_POLY_SET& polySet = aZone->GetFilledPolysList();
+
+ if( polySet.OutlineCount() == 0 ) // Nothing to draw
+ return;
+
+ // Set up drawing options
+ m_gal->SetFillColor( color );
+ m_gal->SetLineWidth( aZone->GetMinThickness() );
+
+ if( displayMode == PCB_RENDER_SETTINGS::DZ_SHOW_FILLED )
+ {
+ m_gal->SetIsFill( true );
+ m_gal->SetIsStroke( true );
+ }
+ else if( displayMode == PCB_RENDER_SETTINGS::DZ_SHOW_OUTLINED )
+ {
+ m_gal->SetIsFill( false );
+ m_gal->SetIsStroke( true );
+ }
+
+ for( int i = 0; i < polySet.OutlineCount(); i++ )
+ {
+ const SHAPE_LINE_CHAIN& outline = polySet.COutline( i );
+ // fixme: GAL drawing API that accepts SHAPEs directly (this fiddling with double<>int conversion
+ // is just a performance hog)
+
+ for( int j = 0; j < outline.PointCount(); j++ )
+ corners.push_back ( (VECTOR2D) outline.CPoint( j ) );
+
+ corners.push_back( (VECTOR2D) outline.CPoint( 0 ) );
+
+ if( displayMode == PCB_RENDER_SETTINGS::DZ_SHOW_FILLED )
+ {
+ m_gal->DrawPolygon( corners );
+ m_gal->DrawPolyline( corners );
+ }
+ else if( displayMode == PCB_RENDER_SETTINGS::DZ_SHOW_OUTLINED )
+ {
+ m_gal->DrawPolyline( corners );
+ }
+
+ corners.clear();
+ }
+ }
+}
+
+
+void PCB_PAINTER::draw( const DIMENSION* aDimension, int aLayer )
+{
+ const COLOR4D& strokeColor = m_pcbSettings.GetColor( aDimension, aLayer );
+
+ m_gal->SetStrokeColor( strokeColor );
+ m_gal->SetIsFill( false );
+ m_gal->SetIsStroke( true );
+ m_gal->SetLineWidth( aDimension->GetWidth() );
+
+ // Draw an arrow
+ m_gal->DrawLine( VECTOR2D( aDimension->m_crossBarO ), VECTOR2D( aDimension->m_crossBarF ) );
+ m_gal->DrawLine( VECTOR2D( aDimension->m_featureLineGO ),
+ VECTOR2D( aDimension->m_featureLineGF ) );
+ m_gal->DrawLine( VECTOR2D( aDimension->m_featureLineDO ),
+ VECTOR2D( aDimension->m_featureLineDF ) );
+ m_gal->DrawLine( VECTOR2D( aDimension->m_crossBarF ), VECTOR2D( aDimension->m_arrowD1F ) );
+ m_gal->DrawLine( VECTOR2D( aDimension->m_crossBarF ), VECTOR2D( aDimension->m_arrowD2F ) );
+ m_gal->DrawLine( VECTOR2D( aDimension->m_crossBarO ), VECTOR2D( aDimension->m_arrowG1F ) );
+ m_gal->DrawLine( VECTOR2D( aDimension->m_crossBarO ), VECTOR2D( aDimension->m_arrowG2F ) );
+
+ // Draw text
+ TEXTE_PCB& text = aDimension->Text();
+ VECTOR2D position( text.GetTextPosition().x, text.GetTextPosition().y );
+ double orientation = text.GetOrientation() * M_PI / 1800.0;
+
+ m_gal->SetLineWidth( text.GetThickness() );
+ m_gal->SetTextAttributes( &text );
+ m_gal->StrokeText( text.GetShownText(), position, orientation );
+}
+
+
+void PCB_PAINTER::draw( const PCB_TARGET* aTarget )
+{
+ const COLOR4D& strokeColor = m_pcbSettings.GetColor( aTarget, aTarget->GetLayer() );
+ VECTOR2D position( aTarget->GetPosition() );
+ double size, radius;
+
+ m_gal->SetLineWidth( aTarget->GetWidth() );
+ m_gal->SetStrokeColor( strokeColor );
+ m_gal->SetIsFill( false );
+ m_gal->SetIsStroke( true );
+
+ m_gal->Save();
+ m_gal->Translate( position );
+
+ if( aTarget->GetShape() )
+ {
+ // shape x
+ m_gal->Rotate( M_PI / 4.0 );
+ size = 2.0 * aTarget->GetSize() / 3.0;
+ radius = aTarget->GetSize() / 2.0;
+ }
+ else
+ {
+ // shape +
+ size = aTarget->GetSize() / 2.0;
+ radius = aTarget->GetSize() / 3.0;
+ }
+
+ m_gal->DrawLine( VECTOR2D( -size, 0.0 ), VECTOR2D( size, 0.0 ) );
+ m_gal->DrawLine( VECTOR2D( 0.0, -size ), VECTOR2D( 0.0, size ) );
+ m_gal->DrawCircle( VECTOR2D( 0.0, 0.0 ), radius );
+
+ m_gal->Restore();
+}
+
+
+void PCB_PAINTER::draw( const MARKER_PCB* aMarker )
+{
+ const int scale = 100000;
+ const VECTOR2D arrow[] = {
+ VECTOR2D( 0 * scale, 0 * scale ),
+ VECTOR2D( 8 * scale, 1 * scale ),
+ VECTOR2D( 4 * scale, 3 * scale ),
+ VECTOR2D( 13 * scale, 8 * scale ),
+ VECTOR2D( 9 * scale, 9 * scale ),
+ VECTOR2D( 8 * scale, 13 * scale ),
+ VECTOR2D( 3 * scale, 4 * scale ),
+ VECTOR2D( 1 * scale, 8 * scale )
+ };
+
+ m_gal->Save();
+ m_gal->Translate( aMarker->GetPosition() );
+ m_gal->SetFillColor( COLOR4D( 1.0, 0.0, 0.0, 1.0 ) );
+ m_gal->SetIsFill( true );
+ m_gal->SetIsStroke( false );
+ m_gal->DrawPolygon( arrow, sizeof( arrow ) / sizeof( VECTOR2D ) );
+ m_gal->Restore();
+}
+
+
+const double PCB_RENDER_SETTINGS::MAX_FONT_SIZE = Millimeter2iu( 10.0 );