You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							586 lines
						
					
					
						
							19 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							586 lines
						
					
					
						
							19 KiB
						
					
					
				| /* | |
|  * This program source code file is part of KiCad, a free EDA CAD application. | |
|  * | |
|  * Copyright (C) 2017 Jon Evans <jon@craftyjon.com> | |
|  * Copyright (C) 2017-2022 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 3 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, see <http://www.gnu.org/licenses/>. | |
|  */ | |
| 
 | |
| #include <gerbview_painter.h> | |
| #include <gal/graphics_abstraction_layer.h> | |
| #include <pgm_base.h> | |
| #include <settings/settings_manager.h> | |
| #include <settings/color_settings.h> | |
| #include <gerbview_settings.h> | |
| #include <convert_basic_shapes_to_polygon.h> | |
| #include <gerbview.h> | |
| #include <trigo.h> | |
|  | |
| #include <dcode.h> | |
| #include <gerber_draw_item.h> | |
| #include <gerber_file_image.h> | |
|  | |
| using namespace KIGFX; | |
| 
 | |
| 
 | |
| GERBVIEW_SETTINGS* gvconfig() | |
| { | |
|     return Pgm().GetSettingsManager().GetAppSettings<GERBVIEW_SETTINGS>(); | |
| } | |
| 
 | |
| 
 | |
| GERBVIEW_RENDER_SETTINGS::GERBVIEW_RENDER_SETTINGS() | |
| { | |
|     m_backgroundColor = COLOR4D::BLACK; | |
| 
 | |
|     m_componentHighlightString = ""; | |
|     m_netHighlightString       = ""; | |
|     m_attributeHighlightString = ""; | |
|     m_dcodeHighlightValue      = -1; | |
| 
 | |
|     update(); | |
| } | |
| 
 | |
| 
 | |
| void GERBVIEW_RENDER_SETTINGS::LoadColors( const COLOR_SETTINGS* aSettings ) | |
| { | |
|     // Layers to draw gerber data read from gerber files: | |
|     for( int i = GERBVIEW_LAYER_ID_START; | |
|          i < GERBVIEW_LAYER_ID_START + GERBER_DRAWLAYERS_COUNT; i++ ) | |
|     { | |
|         COLOR4D baseColor = aSettings->GetColor( i ); | |
| 
 | |
|         if( gvconfig()->m_Display.m_DiffMode ) | |
|             baseColor.a = 0.75; | |
| 
 | |
|         m_layerColors[i] = baseColor; | |
|         m_layerColorsHi[i] = baseColor.Brightened( 0.5 ); | |
|         m_layerColorsSel[i] = baseColor.Brightened( 0.8 ); | |
|         m_layerColorsDark[i] = baseColor.Darkened( 0.25 ); | |
|     } | |
| 
 | |
|     // Draw layers specific to Gerbview: | |
|     // LAYER_DCODES, LAYER_NEGATIVE_OBJECTS, LAYER_GERBVIEW_GRID, LAYER_GERBVIEW_AXES, | |
|     // LAYER_GERBVIEW_BACKGROUND, LAYER_GERBVIEW_DRAWINGSHEET, LAYER_GERBVIEW_PAGE_LIMITS | |
|     for( int i = LAYER_DCODES; i < GERBVIEW_LAYER_ID_END; i++ ) | |
|         m_layerColors[i] = aSettings->GetColor( i ); | |
| 
 | |
|     for( int i = GAL_LAYER_ID_START; i < GAL_LAYER_ID_END; i++ ) | |
|         m_layerColors[i] = aSettings->GetColor( i ); | |
| 
 | |
|     // Ensure the generic LAYER_DRAWINGSHEET has the same color as the specialized | |
|     // LAYER_GERBVIEW_DRAWINGSHEET | |
|     m_layerColors[LAYER_DRAWINGSHEET] = m_layerColors[ LAYER_GERBVIEW_DRAWINGSHEET ]; | |
| 
 | |
|     update(); | |
| } | |
| 
 | |
| 
 | |
| void GERBVIEW_RENDER_SETTINGS::ClearHighlightSelections() | |
| { | |
|     // Clear all highlight selections (dcode, net, component, attribute selection) | |
|     m_componentHighlightString.Empty(); | |
|     m_netHighlightString.Empty(); | |
|     m_attributeHighlightString.Empty(); | |
|     m_dcodeHighlightValue = -1; | |
| } | |
| 
 | |
| COLOR4D GERBVIEW_RENDER_SETTINGS::GetColor( const VIEW_ITEM* aItem, int aLayer ) const | |
| { | |
|     const EDA_ITEM* item = dynamic_cast<const EDA_ITEM*>( aItem ); | |
|     static const COLOR4D transparent = COLOR4D( 0, 0, 0, 0 ); | |
|     const GERBER_DRAW_ITEM* gbrItem = nullptr; | |
| 
 | |
|     if( item && item->Type() == GERBER_DRAW_ITEM_T ) | |
|         gbrItem = static_cast<const GERBER_DRAW_ITEM*>( item ); | |
| 
 | |
|     // All DCODE layers stored under a single color setting | |
|     if( IsDCodeLayer( aLayer ) ) | |
|         return m_layerColors[ LAYER_DCODES ]; | |
| 
 | |
|     if( item && item->IsSelected() ) | |
|         return m_layerColorsSel[aLayer]; | |
| 
 | |
|     if( gbrItem && gbrItem->GetLayerPolarity() ) | |
|     { | |
|         if( gvconfig()->m_Appearance.show_negative_objects ) | |
|             return m_layerColors[LAYER_NEGATIVE_OBJECTS]; | |
|         else | |
|             return transparent; | |
|     } | |
| 
 | |
|     if( !m_netHighlightString.IsEmpty() && gbrItem && | |
|         m_netHighlightString == gbrItem->GetNetAttributes().m_Netname ) | |
|         return m_layerColorsHi[aLayer]; | |
| 
 | |
|     if( !m_componentHighlightString.IsEmpty() && gbrItem && | |
|         m_componentHighlightString == gbrItem->GetNetAttributes().m_Cmpref ) | |
|         return m_layerColorsHi[aLayer]; | |
| 
 | |
|     if( !m_attributeHighlightString.IsEmpty() && gbrItem && gbrItem->GetDcodeDescr() && | |
|         m_attributeHighlightString == gbrItem->GetDcodeDescr()->m_AperFunction ) | |
|         return m_layerColorsHi[aLayer]; | |
| 
 | |
|     if( m_dcodeHighlightValue> 0 && gbrItem && gbrItem->GetDcodeDescr() && | |
|         m_dcodeHighlightValue == gbrItem->GetDcodeDescr()->m_Num_Dcode ) | |
|         return m_layerColorsHi[aLayer]; | |
| 
 | |
|     // Return grayish color for non-highlighted layers in the high contrast mode | |
|     if( m_hiContrastEnabled && m_highContrastLayers.count( aLayer ) == 0) | |
|         return m_hiContrastColor[aLayer]; | |
| 
 | |
|     // 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]; | |
| } | |
| 
 | |
| 
 | |
| bool GERBVIEW_RENDER_SETTINGS::GetShowPageLimits() const | |
| { | |
|     return gvconfig()->m_Display.m_DisplayPageLimits; | |
| } | |
| 
 | |
| 
 | |
| GERBVIEW_PAINTER::GERBVIEW_PAINTER( GAL* aGal ) : | |
|     PAINTER( aGal ) | |
| { | |
| } | |
| 
 | |
| 
 | |
| // TODO(JE): Pull up to PAINTER? | |
| int GERBVIEW_PAINTER::getLineThickness( int aActualThickness ) const | |
| { | |
|     // if items have 0 thickness, draw them with the outline width, otherwise respect the set | |
|     // value (which, no matter how small will produce something) | |
|     if( aActualThickness == 0 ) | |
|         return m_gerbviewSettings.m_outlineWidth; | |
| 
 | |
|     return aActualThickness; | |
| } | |
| 
 | |
| 
 | |
| bool GERBVIEW_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer ) | |
| { | |
|     GERBER_DRAW_ITEM* gbrItem = dynamic_cast<GERBER_DRAW_ITEM*>( const_cast<VIEW_ITEM*>( aItem ) ); | |
| 
 | |
|     if( gbrItem ) | |
|     { | |
|         draw( gbrItem, aLayer ); | |
|         return true; | |
|     } | |
| 
 | |
|     return false; | |
| } | |
| 
 | |
| 
 | |
| // TODO(JE) aItem can't be const because of GetDcodeDescr() | |
| // Probably that can be refactored in GERBER_DRAW_ITEM to allow const here. | |
| void GERBVIEW_PAINTER::draw( /*const*/ GERBER_DRAW_ITEM* aItem, int aLayer ) | |
| { | |
|     VECTOR2D start( aItem->GetABPosition( aItem->m_Start ) );   // TODO(JE) Getter | |
|     VECTOR2D end( aItem->GetABPosition( aItem->m_End ) );       // TODO(JE) Getter | |
|     int      width = aItem->m_Size.x;   // TODO(JE) Getter | |
|     bool     isFilled = true; | |
|     COLOR4D  color; | |
|     // TODO(JE) This doesn't actually work properly for ImageNegative | |
|     bool     isNegative = ( aItem->GetLayerPolarity() ^ aItem->m_GerberImageFile->m_ImageNegative ); | |
| 
 | |
|     // Draw DCODE overlay text | |
|     if( IsDCodeLayer( aLayer ) ) | |
|     { | |
|         wxString  codeText; | |
|         VECTOR2I  textPosition; | |
|         int       textSize; | |
|         EDA_ANGLE orient; | |
| 
 | |
|         if( !aItem->GetTextD_CodePrms( textSize, textPosition, orient ) ) | |
|             return; | |
| 
 | |
|         color = m_gerbviewSettings.GetColor( aItem, aLayer ); | |
|         codeText.Printf( wxT( "D%d" ), aItem->m_DCode ); | |
| 
 | |
|         m_gal->SetIsStroke( true ); | |
|         m_gal->SetIsFill( false ); | |
|         m_gal->SetStrokeColor( color ); | |
|         m_gal->SetFillColor( COLOR4D( 0, 0, 0, 0 ) ); | |
|         m_gal->SetLineWidth( textSize/10 ); | |
|         m_gal->SetFontBold( false ); | |
|         m_gal->SetFontItalic( false ); | |
|         m_gal->SetFontUnderlined( false ); | |
|         m_gal->SetTextMirrored( false ); | |
|         m_gal->SetGlyphSize( VECTOR2D( textSize, textSize) ); | |
|         m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER ); | |
|         m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER ); | |
|         m_gal->BitmapText( codeText, textPosition, orient ); | |
| 
 | |
|         return; | |
|     } | |
| 
 | |
|     color = m_gerbviewSettings.GetColor( aItem, aLayer ); | |
| 
 | |
|     // TODO: Should brightened color be a preference? | |
|     if( aItem->IsBrightened() ) | |
|         color = COLOR4D( 0.0, 1.0, 0.0, 0.75 ); | |
| 
 | |
|     m_gal->SetNegativeDrawMode( isNegative && !gvconfig()->m_Appearance.show_negative_objects ); | |
|     m_gal->SetStrokeColor( color ); | |
|     m_gal->SetFillColor( color ); | |
|     m_gal->SetIsFill( isFilled ); | |
|     m_gal->SetIsStroke( !isFilled ); | |
| 
 | |
|     switch( aItem->m_Shape ) | |
|     { | |
|     case GBR_POLYGON: | |
|     { | |
|         isFilled = gvconfig()->m_Display.m_DisplayPolygonsFill; | |
|         m_gal->SetIsFill( isFilled ); | |
|         m_gal->SetIsStroke( !isFilled ); | |
| 
 | |
|         if( isNegative && !isFilled ) | |
|         { | |
|             m_gal->SetNegativeDrawMode( false ); | |
|             m_gal->SetStrokeColor( GetSettings()->GetColor( aItem, aLayer ) ); | |
|         } | |
| 
 | |
|         if( !isFilled ) | |
|             m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth ); | |
| 
 | |
|         if( aItem->m_AbsolutePolygon.OutlineCount() == 0 ) | |
|         { | |
|             std::vector<VECTOR2I> pts = aItem->m_Polygon.COutline( 0 ).CPoints(); | |
| 
 | |
|             for( auto& pt : pts ) | |
|                 pt = aItem->GetABPosition( pt ); | |
| 
 | |
|             SHAPE_LINE_CHAIN chain( pts ); | |
|             chain.SetClosed( true ); | |
|             aItem->m_AbsolutePolygon.AddOutline( chain ); | |
|         } | |
| 
 | |
|         // Degenerated polygons (having < 3 points) are drawn as lines | |
|         // to avoid issues in draw polygon functions | |
|         if( !isFilled || aItem->m_AbsolutePolygon.COutline( 0 ).PointCount() < 3 ) | |
|             m_gal->DrawPolyline( aItem->m_AbsolutePolygon.COutline( 0 ) ); | |
|         else | |
|         { | |
|             // On Opengl, a not convex filled polygon is usually drawn by using triangles as | |
|             // primitives. CacheTriangulation() can create basic triangle primitives to draw the | |
|             // polygon solid shape on Opengl | |
|             // We use the fastest CacheTriangulation calculation mode: no partition created because | |
|             // the partition is useless in Gerbview, and very time consumming (optimized only | |
|             // for pcbnew that has different internal unit) | |
|             if( m_gal->IsOpenGlEngine() && !aItem->m_AbsolutePolygon.IsTriangulationUpToDate() ) | |
|                 aItem->m_AbsolutePolygon.CacheTriangulation( false /* fastest triangulation calculation mode */ ); | |
| 
 | |
|             m_gal->DrawPolygon( aItem->m_AbsolutePolygon ); | |
|         } | |
| 
 | |
|         break; | |
|     } | |
| 
 | |
|     case GBR_CIRCLE: | |
|     { | |
|         isFilled = gvconfig()->m_Display.m_DisplayLinesFill; | |
|         double radius = GetLineLength( aItem->m_Start, aItem->m_End ); | |
|         m_gal->DrawCircle( start, radius ); | |
|         break; | |
|     } | |
| 
 | |
|     case GBR_ARC: | |
|     { | |
|         isFilled = gvconfig()->m_Display.m_DisplayLinesFill; | |
| 
 | |
|         // These are swapped because wxDC fills arcs counterclockwise and GAL | |
|         // fills them clockwise. | |
|         VECTOR2I arcStart = aItem->m_End; | |
|         VECTOR2I arcEnd = aItem->m_Start; | |
| 
 | |
|         // Gerber arcs are 3-point (start, center, end) | |
|         // GAL needs center, radius, start angle, end angle | |
|         double   radius = GetLineLength( arcStart, aItem->m_ArcCentre ); | |
|         VECTOR2D center = aItem->GetABPosition( aItem->m_ArcCentre ); | |
|         VECTOR2D startVec = VECTOR2D( aItem->GetABPosition( arcStart ) ) - center; | |
|         VECTOR2D endVec = VECTOR2D( aItem->GetABPosition( arcEnd ) ) - center; | |
| 
 | |
|         m_gal->SetIsFill( isFilled ); | |
|         m_gal->SetIsStroke( !isFilled ); | |
|         m_gal->SetLineWidth( isFilled ? width : m_gerbviewSettings.m_outlineWidth ); | |
| 
 | |
|         EDA_ANGLE startAngle( startVec ); | |
|         EDA_ANGLE endAngle( endVec ); | |
| 
 | |
|         // GAL fills in direction of increasing angle, so we have to convert | |
|         // the angle from the -PI to PI domain of atan2() to ensure that | |
|         // the arc goes in the right direction | |
|         if( startAngle > endAngle ) | |
|             endAngle += ANGLE_360; | |
| 
 | |
|         // In Gerber, 360-degree arcs are stored in the file with start equal to end | |
|         if( arcStart == arcEnd ) | |
|             endAngle = startAngle + ANGLE_360; | |
| 
 | |
|         m_gal->DrawArcSegment( center, radius, startAngle, endAngle, width, ARC_HIGH_DEF ); | |
| 
 | |
| #if 0   // Arc Debugging only | |
|         m_gal->SetIsFill( false ); | |
|         m_gal->SetIsStroke( true ); | |
|         m_gal->SetLineWidth( 5 ); | |
|         m_gal->SetStrokeColor( COLOR4D( 0.1, 0.5, 0.0, 0.5 ) ); | |
|         m_gal->DrawLine( center, aItem->GetABPosition( arcStart ) ); | |
|         m_gal->SetStrokeColor( COLOR4D( 0.6, 0.1, 0.0, 0.5 ) ); | |
|         m_gal->DrawLine( center, aItem->GetABPosition( arcEnd ) ); | |
| #endif | |
|  | |
| #if 0   // Bbox arc Debugging only | |
|         m_gal->SetIsFill( false ); | |
|         m_gal->SetIsStroke( true ); | |
|         BOX2I box = aItem->GetBoundingBox(); | |
|         m_gal->SetLineWidth( 5 ); | |
|         m_gal->SetStrokeColor( COLOR4D(0.9, 0.9, 0, 0.4) ); | |
|         // box coordinates are already in AB position. | |
|         m_gal->DrawRectangle( box.GetOrigin(), box.GetEnd() ); | |
| #endif | |
|         break; | |
|     } | |
| 
 | |
|     case GBR_SPOT_CIRCLE: | |
|     case GBR_SPOT_RECT: | |
|     case GBR_SPOT_OVAL: | |
|     case GBR_SPOT_POLY: | |
|     case GBR_SPOT_MACRO: | |
|         isFilled = gvconfig()->m_Display.m_DisplayFlashedItemsFill; | |
|         drawFlashedShape( aItem, isFilled ); | |
|         break; | |
| 
 | |
|     case GBR_SEGMENT: | |
|     { | |
|         /* Plot a line from m_Start to m_End. | |
|          * Usually, a round pen is used, but some gerber files use a rectangular pen | |
|          * In fact, any aperture can be used to plot a line. | |
|          * currently: only a square pen is handled (I believe using a polygon gives a strange plot). | |
|          */ | |
|         isFilled = gvconfig()->m_Display.m_DisplayLinesFill; | |
|         m_gal->SetIsFill( isFilled ); | |
|         m_gal->SetIsStroke( !isFilled ); | |
| 
 | |
|         if( isNegative && !isFilled ) | |
|             m_gal->SetStrokeColor( GetSettings()->GetColor( aItem, aLayer ) ); | |
| 
 | |
|         // TODO(JE) Refactor this to allow const aItem | |
|         D_CODE* code = aItem->GetDcodeDescr(); | |
|         if( code && code->m_Shape == APT_RECT ) | |
|         { | |
|             if( aItem->m_Polygon.OutlineCount() == 0 ) | |
|                 aItem->ConvertSegmentToPolygon(); | |
| 
 | |
|             drawPolygon( aItem, aItem->m_Polygon, isFilled ); | |
|         } | |
|         else | |
|         { | |
|             if( !isFilled ) | |
|                 m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth ); | |
| 
 | |
|             m_gal->DrawSegment( start, end, width ); | |
|         } | |
|         break; | |
|     } | |
| 
 | |
|     default: | |
|         wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) ); | |
|         break; | |
|     } | |
|     m_gal->SetNegativeDrawMode( false ); | |
| 
 | |
|     // Enable for bounding box debugging | |
|     #if 0 | |
|     const BOX2I& bb = aItem->ViewBBox(); | |
|     m_gal->SetIsStroke( true ); | |
|     m_gal->SetIsFill( true ); | |
|     m_gal->SetLineWidth( 3 ); | |
|     m_gal->SetStrokeColor( COLOR4D(0.9, 0.9, 0, 0.4) ); | |
|     m_gal->SetFillColor( COLOR4D(0.9, 0.9, 0, 0.1) ); | |
|     m_gal->DrawRectangle( bb.GetOrigin(), bb.GetEnd() ); | |
|     #endif | |
| } | |
| 
 | |
| 
 | |
| void GERBVIEW_PAINTER::drawPolygon( GERBER_DRAW_ITEM* aParent, const SHAPE_POLY_SET& aPolygon, | |
|                                     bool aFilled, bool aShift ) | |
| { | |
|     wxASSERT( aPolygon.OutlineCount() == 1 ); | |
| 
 | |
|     if( aPolygon.OutlineCount() == 0 ) | |
|         return; | |
| 
 | |
|     SHAPE_POLY_SET poly; | |
|     poly.NewOutline(); | |
|     const std::vector<VECTOR2I> pts = aPolygon.COutline( 0 ).CPoints(); | |
|     VECTOR2I offset = aShift ? VECTOR2I( aParent->m_Start ) : VECTOR2I( 0, 0 ); | |
| 
 | |
|     for( const VECTOR2I& pt : pts ) | |
|         poly.Append( aParent->GetABPosition( pt + offset ) ); | |
| 
 | |
|     if( !gvconfig()->m_Display.m_DisplayPolygonsFill ) | |
|         m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth ); | |
| 
 | |
|     if( !aFilled ) | |
|         m_gal->DrawPolyline( poly.COutline( 0 ) ); | |
|     else | |
|         m_gal->DrawPolygon( poly ); | |
| } | |
| 
 | |
| 
 | |
| void GERBVIEW_PAINTER::drawFlashedShape( GERBER_DRAW_ITEM* aItem, bool aFilled ) | |
| { | |
|     D_CODE* code = aItem->GetDcodeDescr(); | |
| 
 | |
|     wxASSERT_MSG( code, wxT( "drawFlashedShape: Item has no D_CODE!" ) ); | |
| 
 | |
|     if( !code ) | |
|         return; | |
| 
 | |
|     m_gal->SetIsFill( aFilled ); | |
|     m_gal->SetIsStroke( !aFilled ); | |
|     m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth ); | |
| 
 | |
|     switch( aItem->m_Shape ) | |
|     { | |
|     case GBR_SPOT_CIRCLE: | |
|     { | |
|         int radius = code->m_Size.x >> 1; | |
|         VECTOR2D start( aItem->GetABPosition( aItem->m_Start ) ); | |
| 
 | |
|         if( !aFilled || code->m_DrillShape == APT_DEF_NO_HOLE ) | |
|         { | |
|             m_gal->DrawCircle( start, radius ); | |
|         } | |
|         else    // rectangular hole | |
|         { | |
|             if( code->m_Polygon.OutlineCount() == 0 ) | |
|                 code->ConvertShapeToPolygon( aItem ); | |
| 
 | |
|             drawPolygon( aItem, code->m_Polygon, aFilled, true ); | |
|         } | |
| 
 | |
|         break; | |
|     } | |
| 
 | |
|     case GBR_SPOT_RECT: | |
|     { | |
|         VECTOR2I codeStart; | |
|         VECTOR2I aShapePos = aItem->m_Start; | |
|         codeStart.x = aShapePos.x - code->m_Size.x / 2; | |
|         codeStart.y = aShapePos.y - code->m_Size.y / 2; | |
|         VECTOR2I codeEnd = codeStart + code->m_Size; | |
|         codeStart = aItem->GetABPosition( codeStart ); | |
|         codeEnd = aItem->GetABPosition( codeEnd ); | |
| 
 | |
|         if( !aFilled || code->m_DrillShape == APT_DEF_NO_HOLE  ) | |
|         { | |
|             m_gal->DrawRectangle( VECTOR2D( codeStart ), VECTOR2D( codeEnd ) ); | |
|         } | |
|         else | |
|         { | |
|             if( code->m_Polygon.OutlineCount() == 0 ) | |
|                 code->ConvertShapeToPolygon( aItem ); | |
| 
 | |
|             drawPolygon( aItem, code->m_Polygon, aFilled, true ); | |
|         } | |
|         break; | |
|     } | |
| 
 | |
|     case GBR_SPOT_OVAL: | |
|     { | |
|         int radius = 0; | |
| 
 | |
|         VECTOR2I codeStart = aItem->m_Start; | |
|         VECTOR2I codeEnd = aItem->m_Start; | |
| 
 | |
|         if( code->m_Size.x > code->m_Size.y )   // horizontal oval | |
|         { | |
|             int delta = (code->m_Size.x - code->m_Size.y) / 2; | |
|             codeStart.x -= delta; | |
|             codeEnd.x   += delta; | |
|             radius   = code->m_Size.y; | |
|         } | |
|         else   // horizontal oval | |
|         { | |
|             int delta = (code->m_Size.y - code->m_Size.x) / 2; | |
|             codeStart.y -= delta; | |
|             codeEnd.y   += delta; | |
|             radius   = code->m_Size.x; | |
|         } | |
| 
 | |
|         codeStart = aItem->GetABPosition( codeStart ); | |
|         codeEnd = aItem->GetABPosition( codeEnd ); | |
| 
 | |
|         if( !aFilled || code->m_DrillShape == APT_DEF_NO_HOLE ) | |
|         { | |
|             m_gal->DrawSegment( codeStart, codeEnd, radius ); | |
|         } | |
|         else | |
|         { | |
|             if( code->m_Polygon.OutlineCount() == 0 ) | |
|                 code->ConvertShapeToPolygon( aItem ); | |
| 
 | |
|             drawPolygon( aItem, code->m_Polygon, aFilled, true ); | |
|         } | |
|         break; | |
|     } | |
| 
 | |
|     case GBR_SPOT_POLY: | |
|         if( code->m_Polygon.OutlineCount() == 0 ) | |
|             code->ConvertShapeToPolygon( aItem ); | |
| 
 | |
|         drawPolygon( aItem, code->m_Polygon, aFilled, true ); | |
|         break; | |
| 
 | |
|     case GBR_SPOT_MACRO: | |
|         drawApertureMacro( aItem, aFilled ); | |
|         break; | |
| 
 | |
|     default: | |
|         wxASSERT_MSG( false, wxT( "Unknown Gerber flashed shape!" ) ); | |
|         break; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| void GERBVIEW_PAINTER::drawApertureMacro( GERBER_DRAW_ITEM* aParent, bool aFilled ) | |
| { | |
|     D_CODE*         code = aParent->GetDcodeDescr(); | |
|     APERTURE_MACRO* macro = code->GetMacro(); | |
|     SHAPE_POLY_SET* macroShape = macro->GetApertureMacroShape( aParent, aParent->m_Start ); | |
| 
 | |
|     if( !gvconfig()->m_Display.m_DisplayPolygonsFill ) | |
|         m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth ); | |
| 
 | |
|     if( !aFilled ) | |
|     { | |
|         for( int i = 0; i < macroShape->OutlineCount(); i++ ) | |
|             m_gal->DrawPolyline( macroShape->COutline( i ) ); | |
|     } | |
|     else | |
|     { | |
|         m_gal->DrawPolygon( *macroShape ); | |
|     } | |
| } | |
| 
 | |
| 
 | |
| const double GERBVIEW_RENDER_SETTINGS::MAX_FONT_SIZE = gerbIUScale.mmToIU( 10.0 );
 |