bool DIALOG_SHIM::Show( bool show ) { bool ret; const char* hash_key; if( m_hash_key.size() ) { // a special case like EDA_LIST_DIALOG, which has multiple uses. hash_key = m_hash_key.c_str(); } else { hash_key = typeid(*this).name(); } // Show or hide the window. If hiding, save current position and size. // If showing, use previous position and size. if( show ) { wxDialog::Raise(); // Needed on OS X and some other window managers (i.e. Unity) ret = wxDialog::Show( show ); // classname is key, returns a zeroed out default EDA_RECT if none existed before. EDA_RECT r = class_map[ hash_key ]; if( r.GetSize().x != 0 && r.GetSize().y != 0 ) SetSize( r.GetPosition().x, r.GetPosition().y, r.GetSize().x, r.GetSize().y, 0 ); } else { // Save the dialog's position & size before hiding, using classname as key EDA_RECT r( wxDialog::GetPosition(), wxDialog::GetSize() ); class_map[ hash_key ] = r; ret = wxDialog::Show( show ); } return ret; }
const BOX2I D_PAD::ViewBBox() const { // Bounding box includes soldermask too int solderMaskMargin = GetSolderMaskMargin(); VECTOR2I solderPasteMargin = VECTOR2D( GetSolderPasteMargin() ); EDA_RECT bbox = GetBoundingBox(); // Look for the biggest possible bounding box int xMargin = std::max( solderMaskMargin, solderPasteMargin.x ); int yMargin = std::max( solderMaskMargin, solderPasteMargin.y ); return BOX2I( VECTOR2I( bbox.GetOrigin() ) - VECTOR2I( xMargin, yMargin ), VECTOR2I( bbox.GetSize() ) + VECTOR2I( 2 * xMargin, 2 * yMargin ) ); }
void SELECTION_TOOL::findCallback( BOARD_ITEM* aItem ) { clearSelection(); if( aItem ) { select( aItem ); EDA_RECT bbox = aItem->GetBoundingBox(); BOX2D viewport( VECTOR2D( bbox.GetOrigin() ), VECTOR2D( bbox.GetSize() ) ); getView()->SetViewport( viewport ); // Inform other potentially interested tools m_toolMgr->ProcessEvent( SelectedEvent ); } m_frame->GetGalCanvas()->ForceRefresh(); }
const BOX2I MODULE::ViewBBox() const { EDA_RECT fpRect = GetFootprintRect(); return BOX2I( VECTOR2I( fpRect.GetOrigin() ), VECTOR2I( fpRect.GetSize() ) ); }
/** * Function idf_export_outline * retrieves line segment information from the edge layer and compiles * the data into a form which can be output as an IDFv3 compliant * BOARD_OUTLINE section. */ static void idf_export_outline( BOARD* aPcb, IDF3_BOARD& aIDFBoard ) { double scale = aIDFBoard.GetUserScale(); DRAWSEGMENT* graphic; // KiCad graphical item IDF_POINT sp, ep; // start and end points from KiCad item std::list< IDF_SEGMENT* > lines; // IDF intermediate form of KiCad graphical item IDF_OUTLINE* outline = NULL; // graphical items forming an outline or cutout // NOTE: IMPLEMENTATION // If/when component cutouts are allowed, we must implement them separately. Cutouts // must be added to the board outline section and not to the Other Outline section. // The module cutouts should be handled via the idf_export_module() routine. double offX, offY; aIDFBoard.GetUserOffset( offX, offY ); // Retrieve segments and arcs from the board for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() ) { if( item->Type() != PCB_LINE_T || item->GetLayer() != Edge_Cuts ) continue; graphic = (DRAWSEGMENT*) item; switch( graphic->GetShape() ) { case S_SEGMENT: { if( ( graphic->GetStart().x == graphic->GetEnd().x ) && ( graphic->GetStart().y == graphic->GetEnd().y ) ) break; sp.x = graphic->GetStart().x * scale + offX; sp.y = -graphic->GetStart().y * scale + offY; ep.x = graphic->GetEnd().x * scale + offX; ep.y = -graphic->GetEnd().y * scale + offY; IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep ); if( seg ) lines.push_back( seg ); } break; case S_ARC: { if( ( graphic->GetCenter().x == graphic->GetArcStart().x ) && ( graphic->GetCenter().y == graphic->GetArcStart().y ) ) break; sp.x = graphic->GetCenter().x * scale + offX; sp.y = -graphic->GetCenter().y * scale + offY; ep.x = graphic->GetArcStart().x * scale + offX; ep.y = -graphic->GetArcStart().y * scale + offY; IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep, -graphic->GetAngle() / 10.0, true ); if( seg ) lines.push_back( seg ); } break; case S_CIRCLE: { if( graphic->GetRadius() == 0 ) break; sp.x = graphic->GetCenter().x * scale + offX; sp.y = -graphic->GetCenter().y * scale + offY; ep.x = sp.x - graphic->GetRadius() * scale; ep.y = sp.y; // Circles must always have an angle of +360 deg. to appease // quirky MCAD implementations of IDF. IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep, 360.0, true ); if( seg ) lines.push_back( seg ); } break; default: break; } } // if there is no outline then use the bounding box if( lines.empty() ) { goto UseBoundingBox; } // get the board outline and write it out // note: we do not use a try/catch block here since we intend // to simply ignore unclosed loops and continue processing // until we're out of segments to process outline = new IDF_OUTLINE; IDF3::GetOutline( lines, *outline ); if( outline->empty() ) goto UseBoundingBox; aIDFBoard.AddBoardOutline( outline ); outline = NULL; // get all cutouts and write them out while( !lines.empty() ) { if( !outline ) outline = new IDF_OUTLINE; IDF3::GetOutline( lines, *outline ); if( outline->empty() ) { outline->Clear(); continue; } aIDFBoard.AddBoardOutline( outline ); outline = NULL; } return; UseBoundingBox: // clean up if necessary while( !lines.empty() ) { delete lines.front(); lines.pop_front(); } if( outline ) outline->Clear(); else outline = new IDF_OUTLINE; // fetch a rectangular bounding box for the board; // there is always some uncertainty in the board dimensions // computed via ComputeBoundingBox() since this depends on the // individual module entities. EDA_RECT bbbox = aPcb->ComputeBoundingBox( true ); // convert to mm and compensate for an assumed LINE_WIDTH line thickness double x = ( bbbox.GetOrigin().x + LINE_WIDTH / 2 ) * scale + offX; double y = ( bbbox.GetOrigin().y + LINE_WIDTH / 2 ) * scale + offY; double dx = ( bbbox.GetSize().x - LINE_WIDTH ) * scale; double dy = ( bbbox.GetSize().y - LINE_WIDTH ) * scale; double px[4], py[4]; px[0] = x; py[0] = y; px[1] = x; py[1] = y + dy; px[2] = x + dx; py[2] = y + dy; px[3] = x + dx; py[3] = y; IDF_POINT p1, p2; p1.x = px[3]; p1.y = py[3]; p2.x = px[0]; p2.y = py[0]; outline->push( new IDF_SEGMENT( p1, p2 ) ); for( int i = 1; i < 4; ++i ) { p1.x = px[i - 1]; p1.y = py[i - 1]; p2.x = px[i]; p2.y = py[i]; outline->push( new IDF_SEGMENT( p1, p2 ) ); } aIDFBoard.AddBoardOutline( outline ); }
const BOX2I GERBER_DRAW_ITEM::ViewBBox() const { EDA_RECT bbox = GetBoundingBox(); return BOX2I( VECTOR2I( bbox.GetOrigin() ), VECTOR2I( bbox.GetSize() ) ); }
bool PCB_EDIT_FRAME::AppendBoardFile( const wxString& aFullFileName, int aCtl ) { IO_MGR::PCB_FILE_T pluginType = plugin_type( aFullFileName, aCtl ); PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); // keep trace of existing items, in order to know what are the new items // (for undo command for instance) // Tracks are inserted, not append, so mark existing tracks to know what are // the new tracks for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) track->SetFlags( FLAG0 ); // Other items are append to the item list, so keep trace to the // last existing item is enough MODULE* module = GetBoard()->m_Modules.GetLast(); BOARD_ITEM* drawing = GetBoard()->m_Drawings.GetLast(); int zonescount = GetBoard()->GetAreaCount(); // Keep also the count of copper layers, because we can happen boards // with different copper layers counts, // and the enabled layers int initialCopperLayerCount = GetBoard()->GetCopperLayerCount(); LSET initialEnabledLayers = GetBoard()->GetEnabledLayers(); try { PROPERTIES props; char xbuf[30]; char ybuf[30]; // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet. sprintf( xbuf, "%d", GetPageSizeIU().x ); sprintf( ybuf, "%d", GetPageSizeIU().y ); props["page_width"] = xbuf; props["page_height"] = ybuf; GetDesignSettings().m_NetClasses.Clear(); pi->Load( aFullFileName, GetBoard(), &props ); } catch( const IO_ERROR& ioe ) { for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) track->ClearFlags( FLAG0 ); wxString msg = wxString::Format( _( "Error loading board.\n%s" ), GetChars( ioe.What() ) ); DisplayError( this, msg ); return false; } // Now prepare a block move command to place the new items, and // prepare the undo command. BLOCK_SELECTOR& blockmove = GetScreen()->m_BlockLocate; HandleBlockBegin( NULL, BLOCK_PRESELECT_MOVE, wxPoint( 0, 0) ); PICKED_ITEMS_LIST& blockitemsList = blockmove.GetItems(); PICKED_ITEMS_LIST undoListPicker; ITEM_PICKER picker( NULL, UR_NEW ); EDA_RECT bbox; // the new items bounding box, for block move bool bboxInit = true; // true until the bounding box is initialized for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) { if( track->GetFlags() & FLAG0 ) { track->ClearFlags( FLAG0 ); continue; } track->SetFlags( IS_MOVED ); picker.SetItem( track ); undoListPicker.PushItem( picker ); blockitemsList.PushItem( picker ); if( bboxInit ) bbox = track->GetBoundingBox(); else bbox.Merge( track->GetBoundingBox() ); bboxInit = false; } if( module ) module = module->Next(); else module = GetBoard()->m_Modules; for( ; module; module = module->Next() ) { module->SetFlags( IS_MOVED ); picker.SetItem( module ); undoListPicker.PushItem( picker ); blockitemsList.PushItem( picker ); if( bboxInit ) bbox = module->GetBoundingBox(); else bbox.Merge( module->GetBoundingBox() ); bboxInit = false; } if( drawing ) drawing = drawing->Next(); else drawing = GetBoard()->m_Drawings; for( ; drawing; drawing = drawing->Next() ) { drawing->SetFlags( IS_MOVED ); picker.SetItem( drawing ); undoListPicker.PushItem( picker ); blockitemsList.PushItem( picker ); if( bboxInit ) bbox = drawing->GetBoundingBox(); else bbox.Merge( drawing->GetBoundingBox() ); bboxInit = false; } for( ZONE_CONTAINER* zone = GetBoard()->GetArea( zonescount ); zone; zone = GetBoard()->GetArea( zonescount ) ) { zone->SetFlags( IS_MOVED ); picker.SetItem( zone ); undoListPicker.PushItem( picker ); blockitemsList.PushItem( picker ); zonescount++; if( bboxInit ) bbox = zone->GetBoundingBox(); else bbox.Merge( zone->GetBoundingBox() ); bboxInit = false; } SaveCopyInUndoList( undoListPicker, UR_NEW ); // we should not ask PLUGINs to do these items: int copperLayerCount = GetBoard()->GetCopperLayerCount(); if( copperLayerCount > initialCopperLayerCount ) GetBoard()->SetCopperLayerCount( copperLayerCount ); // Enable all used layers, and make them visible: LSET enabledLayers = GetBoard()->GetEnabledLayers(); enabledLayers |= initialEnabledLayers; GetBoard()->SetEnabledLayers( enabledLayers ); GetBoard()->SetVisibleLayers( enabledLayers ); ReCreateLayerBox(); ReFillLayerWidget(); if( IsGalCanvasActive() ) static_cast<PCB_DRAW_PANEL_GAL*>( GetGalCanvas() )->SyncLayersVisibility( GetBoard() ); GetBoard()->BuildListOfNets(); GetBoard()->SynchronizeNetsAndNetClasses(); SetStatusText( wxEmptyString ); BestZoom(); // Finish block move command: wxPoint cpos = GetNearestGridPosition( bbox.Centre() ); blockmove.SetOrigin( bbox.GetOrigin() ); blockmove.SetSize( bbox.GetSize() ); blockmove.SetLastCursorPosition( cpos ); HandleBlockEnd( NULL ); return true; }
/** Set up most plot options for plotting a board (especially the viewport) * Important thing: * page size is the 'drawing' page size, * paper size is the physical page size */ static void initializePlotter( PLOTTER *aPlotter, BOARD * aBoard, PCB_PLOT_PARAMS *aPlotOpts ) { PAGE_INFO pageA4( wxT( "A4" ) ); const PAGE_INFO& pageInfo = aBoard->GetPageSettings(); const PAGE_INFO* sheet_info; double paperscale; // Page-to-paper ratio wxSize paperSizeIU; wxSize pageSizeIU( pageInfo.GetSizeIU() ); bool autocenter = false; /* Special options: to fit the sheet to an A4 sheet replace the paper size. However there is a difference between the autoscale and the a4paper option: - Autoscale fits the board to the paper size - A4paper fits the original paper size to an A4 sheet - Both of them fit the board to an A4 sheet */ if( aPlotOpts->GetA4Output() ) // Fit paper to A4 { sheet_info = &pageA4; paperSizeIU = pageA4.GetSizeIU(); paperscale = (double) paperSizeIU.x / pageSizeIU.x; autocenter = true; } else { sheet_info = &pageInfo; paperSizeIU = pageSizeIU; paperscale = 1; // Need autocentering only if scale is not 1:1 autocenter = (aPlotOpts->GetScale() != 1.0); } EDA_RECT bbox = aBoard->ComputeBoundingBox(); wxPoint boardCenter = bbox.Centre(); wxSize boardSize = bbox.GetSize(); double compound_scale; /* Fit to 80% of the page if asked; it could be that the board is empty, * in this case regress to 1:1 scale */ if( aPlotOpts->GetAutoScale() && boardSize.x > 0 && boardSize.y > 0 ) { double xscale = (paperSizeIU.x * 0.8) / boardSize.x; double yscale = (paperSizeIU.y * 0.8) / boardSize.y; compound_scale = std::min( xscale, yscale ) * paperscale; } else compound_scale = aPlotOpts->GetScale() * paperscale; /* For the plot offset we have to keep in mind the auxiliary origin too: if autoscaling is off we check that plot option (i.e. autoscaling overrides auxiliary origin) */ wxPoint offset( 0, 0); if( autocenter ) { offset.x = KiROUND( boardCenter.x - ( paperSizeIU.x / 2.0 ) / compound_scale ); offset.y = KiROUND( boardCenter.y - ( paperSizeIU.y / 2.0 ) / compound_scale ); } else { if( aPlotOpts->GetUseAuxOrigin() ) offset = aBoard->GetAuxOrigin(); } /* Configure the plotter object with all the stuff computed and most of that taken from the options */ aPlotter->SetPageSettings( *sheet_info ); aPlotter->SetViewport( offset, IU_PER_DECIMILS, compound_scale, aPlotOpts->GetMirror() ); aPlotter->SetDefaultLineWidth( aPlotOpts->GetLineWidth() ); aPlotter->SetCreator( wxT( "PCBNEW" ) ); aPlotter->SetColorMode( false ); // default is plot in Black and White. aPlotter->SetTextMode( aPlotOpts->GetTextMode() ); }
void CINFO3D_VISU::InitSettings( REPORTER *aStatusTextReporter ) { wxLogTrace( m_logTrace, wxT( "CINFO3D_VISU::InitSettings" ) ); // Calculates the board bounding box // First, use only the board outlines EDA_RECT bbbox = m_board->ComputeBoundingBox( true ); // If no outlines, use the board with items if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) ) bbbox = m_board->ComputeBoundingBox( false ); // Gives a non null size to avoid issues in zoom / scale calculations if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) ) bbbox.Inflate( Millimeter2iu( 10 ) ); m_boardSize = bbbox.GetSize(); m_boardPos = bbbox.Centre(); wxASSERT( (m_boardSize.x > 0) && (m_boardSize.y > 0) ); m_boardPos.y = -m_boardPos.y; // The y coord is inverted in 3D viewer m_copperLayersCount = m_board->GetCopperLayerCount(); // Ensure the board has 2 sides for 3D views, because it is hard to find // a *really* single side board in the true life... if( m_copperLayersCount < 2 ) m_copperLayersCount = 2; // Calculate the convertion to apply to all positions. m_biuTo3Dunits = RANGE_SCALE_3D / std::max( m_boardSize.x, m_boardSize.y ); // Calculate factors for cicle segment approximation m_calc_seg_min_factor3DU = (float)( SEG_MIN_FACTOR_BIU * m_biuTo3Dunits ); m_calc_seg_max_factor3DU = (float)( SEG_MAX_FACTOR_BIU * m_biuTo3Dunits ); m_epoxyThickness3DU = m_board->GetDesignSettings().GetBoardThickness() * m_biuTo3Dunits; // !TODO: use value defined by user (currently use default values by ctor m_copperThickness3DU = COPPER_THICKNESS * m_biuTo3Dunits; m_nonCopperLayerThickness3DU = TECH_LAYER_THICKNESS * m_biuTo3Dunits; // Init Z position of each layer // calculate z position for each copper layer // Zstart = -m_epoxyThickness / 2.0 is the z position of the back (bottom layer) (layer id = 31) // Zstart = +m_epoxyThickness / 2.0 is the z position of the front (top layer) (layer id = 0) // all unused copper layer z position are set to 0 // ____==__________==________==______ <- Bottom = +m_epoxyThickness / 2.0, // | | Top = Bottom + m_copperThickness // |__________________________________| // == == == == <- Bottom = -m_epoxyThickness / 2.0, // Top = Bottom - m_copperThickness unsigned int layer; for( layer = 0; layer < m_copperLayersCount; ++layer ) { m_layerZcoordBottom[layer] = m_epoxyThickness3DU / 2.0f - (m_epoxyThickness3DU * layer / (m_copperLayersCount - 1) ); if( layer < (m_copperLayersCount / 2) ) m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] + m_copperThickness3DU; else m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] - m_copperThickness3DU; } #define layerThicknessMargin 1.1 const float zpos_offset = m_nonCopperLayerThickness3DU * layerThicknessMargin; // Fill remaining unused copper layers and back layer zpos // with -m_epoxyThickness / 2.0 for( ; layer < MAX_CU_LAYERS; layer++ ) { m_layerZcoordBottom[layer] = -(m_epoxyThickness3DU / 2.0f); m_layerZcoordTop[layer] = -(m_epoxyThickness3DU / 2.0f) - m_copperThickness3DU; } // This is the top of the copper layer thickness. const float zpos_copperTop_back = m_layerZcoordTop[B_Cu]; const float zpos_copperTop_front = m_layerZcoordTop[F_Cu]; // calculate z position for each non copper layer // Solder mask and Solder paste have the same Z position for( int layer_id = MAX_CU_LAYERS; layer_id < LAYER_ID_COUNT; ++layer_id ) { float zposTop; float zposBottom; switch( layer_id ) { case B_Adhes: zposBottom = zpos_copperTop_back - 2.0f * zpos_offset; zposTop = zposBottom - m_nonCopperLayerThickness3DU; break; case F_Adhes: zposBottom = zpos_copperTop_front + 2.0f * zpos_offset; zposTop = zposBottom + m_nonCopperLayerThickness3DU; break; case B_Mask: case B_Paste: zposBottom = zpos_copperTop_back; zposTop = zpos_copperTop_back - m_nonCopperLayerThickness3DU; break; case F_Mask: case F_Paste: zposTop = zpos_copperTop_front + m_nonCopperLayerThickness3DU; zposBottom = zpos_copperTop_front; break; case B_SilkS: zposBottom = zpos_copperTop_back - 1.0f * zpos_offset; zposTop = zposBottom - m_nonCopperLayerThickness3DU; break; case F_SilkS: zposBottom = zpos_copperTop_front + 1.0f * zpos_offset; zposTop = zposBottom + m_nonCopperLayerThickness3DU; break; // !TODO: review default: zposTop = zpos_copperTop_front + (layer_id - MAX_CU_LAYERS + 3.0f) * zpos_offset; zposBottom = zposTop - m_nonCopperLayerThickness3DU; break; } m_layerZcoordTop[layer_id] = zposTop; m_layerZcoordBottom[layer_id] = zposBottom; } m_boardCenter = SFVEC3F( m_boardPos.x * m_biuTo3Dunits, m_boardPos.y * m_biuTo3Dunits, 0.0f ); SFVEC3F boardSize = SFVEC3F( m_boardSize.x * m_biuTo3Dunits, m_boardSize.y * m_biuTo3Dunits, 0.0f ); boardSize /= 2.0f; SFVEC3F boardMin = (m_boardCenter - boardSize); SFVEC3F boardMax = (m_boardCenter + boardSize); boardMin.z = m_layerZcoordTop[B_Adhes]; boardMax.z = m_layerZcoordTop[F_Adhes]; m_boardBoudingBox = CBBOX( boardMin, boardMax ); #ifdef PRINT_STATISTICS_3D_VIEWER unsigned stats_startCreateBoardPolyTime = GetRunningMicroSecs(); #endif if( aStatusTextReporter ) aStatusTextReporter->Report( _( "Build board body" ) ); createBoardPolygon(); #ifdef PRINT_STATISTICS_3D_VIEWER unsigned stats_stopCreateBoardPolyTime = GetRunningMicroSecs(); unsigned stats_startCreateLayersTime = stats_stopCreateBoardPolyTime; #endif if( aStatusTextReporter ) aStatusTextReporter->Report( _( "Create layers" ) ); createLayers( aStatusTextReporter ); #ifdef PRINT_STATISTICS_3D_VIEWER unsigned stats_stopCreateLayersTime = GetRunningMicroSecs(); printf( "CINFO3D_VISU::InitSettings times\n" ); printf( " CreateBoardPoly: %.3f ms\n", (float)( stats_stopCreateBoardPolyTime - stats_startCreateBoardPolyTime ) / 1e3 ); printf( " CreateLayers and holes: %.3f ms\n", (float)( stats_stopCreateLayersTime - stats_startCreateLayersTime ) / 1e3 ); printf( "\n" ); #endif }
bool PCB_BASE_FRAME::ExportToHpglFile( const wxString& aFullFileName, int aLayer, EDA_DRAW_MODE_T aTraceMode ) { wxSize boardSize; wxPoint boardCenter; bool center = false; double scale; wxPoint offset; LOCALE_IO toggle; FILE* output_file = wxFopen( aFullFileName, wxT( "wt" ) ); if( output_file == NULL ) { return false; } // Compute pen_dim (from g_m_HPGLPenDiam in mils) in pcb units, // with plot scale (if Scale is 2, pen diameter is always g_m_HPGLPenDiam // so apparent pen diam is real pen diam / Scale int pen_diam = wxRound( (g_PcbPlotOptions.m_HPGLPenDiam * U_PCB) / g_PcbPlotOptions.m_PlotScale ); // compute pen_overlay (from g_m_HPGLPenOvr in mils) with plot scale if( g_PcbPlotOptions.m_HPGLPenOvr < 0 ) g_PcbPlotOptions.m_HPGLPenOvr = 0; if( g_PcbPlotOptions.m_HPGLPenOvr >= g_PcbPlotOptions.m_HPGLPenDiam ) g_PcbPlotOptions.m_HPGLPenOvr = g_PcbPlotOptions.m_HPGLPenDiam - 1; int pen_overlay = wxRound( g_PcbPlotOptions.m_HPGLPenOvr * 10.0 / g_PcbPlotOptions.m_PlotScale ); if( g_PcbPlotOptions.m_PlotScale != 1.0 || g_PcbPlotOptions.m_AutoScale ) { // when scale != 1.0 we must calculate the position in page // because actual position has no meaning center = true; } wxSize pageSizeIU = GetPageSizeIU(); // Calculate the center of the PCB EDA_RECT bbbox = GetBoardBoundingBox(); boardSize = bbbox.GetSize(); boardCenter = bbbox.Centre(); if( g_PcbPlotOptions.m_AutoScale ) // Optimum scale { // Fit to 80% of the page double Xscale = ( ( pageSizeIU.x * 0.8 ) / boardSize.x ); double Yscale = ( ( pageSizeIU.y * 0.8 ) / boardSize.y ); scale = MIN( Xscale, Yscale ); } else { scale = g_PcbPlotOptions.m_PlotScale; } // Calculate the page size offset. if( center ) { offset.x = wxRound( (double) boardCenter.x - ( (double) pageSizeIU.x / 2.0 ) / scale ); offset.y = wxRound( (double) boardCenter.y - ( (double) pageSizeIU.y / 2.0 ) / scale ); } else { offset.x = 0; offset.y = 0; } HPGL_PLOTTER* plotter = new HPGL_PLOTTER(); plotter->SetPageSettings( GetPageSettings() ); plotter->set_viewport( offset, scale, g_PcbPlotOptions.m_PlotMirror ); plotter->set_default_line_width( g_PcbPlotOptions.m_PlotLineWidth ); plotter->set_creator( wxT( "PCBNEW-HPGL" ) ); plotter->set_filename( aFullFileName ); plotter->set_pen_speed( g_PcbPlotOptions.m_HPGLPenSpeed ); plotter->set_pen_number( g_PcbPlotOptions.m_HPGLPenNum ); plotter->set_pen_overlap( pen_overlay ); plotter->set_pen_diameter( pen_diam ); plotter->start_plot( output_file ); // The worksheet is not significant with scale!=1... It is with paperscale!=1, anyway if( g_PcbPlotOptions.m_PlotFrameRef && !center ) PlotWorkSheet( plotter, GetScreen() ); Plot_Layer( plotter, aLayer, aTraceMode ); plotter->end_plot(); delete plotter; return true; }