void FOOTPRINT_EDIT_FRAME::Edit_Edge_Width( EDGE_MODULE* aEdge ) { MODULE* module = GetBoard()->m_Modules; SaveCopyInUndoList( module, UR_CHANGED ); if( aEdge == NULL ) { for( BOARD_ITEM *item = module->GraphicalItemsList(); item; item = item->Next() ) { aEdge = dyn_cast<EDGE_MODULE*>( item ); if( aEdge ) aEdge->SetWidth( GetDesignSettings().GetLineThickness( aEdge->GetLayer() ) ); } } else { aEdge->SetWidth( GetDesignSettings().GetLineThickness( aEdge->GetLayer() ) ); } OnModify(); module->CalculateBoundingBox(); module->SetLastEditTime(); }
void FOOTPRINT_EDIT_FRAME::Edit_Edge_Width( EDGE_MODULE* aEdge ) { MODULE* module = GetBoard()->m_Modules; SaveCopyInUndoList( module, UR_MODEDIT ); if( aEdge == NULL ) { aEdge = (EDGE_MODULE*) (BOARD_ITEM*) module->m_Drawings; for( ; aEdge != NULL; aEdge = aEdge->Next() ) { if( aEdge->Type() != PCB_MODULE_EDGE_T ) continue; aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth ); } } else { aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth ); } OnModify(); module->CalculateBoundingBox(); module->m_LastEdit_Time = time( NULL ); }
void PCB_BASE_FRAME::DeletePad( D_PAD* aPad, bool aQuery ) { if( aPad == NULL ) return; MODULE* module = aPad->GetParent(); module->SetLastEditTime(); // aQuery = true to prompt for confirmation, false to delete silently if( aQuery ) { wxString msg = wxString::Format( _( "Delete pad (footprint %s %s)?" ), module->GetReference(), module->GetValue() ); if( !IsOK( this, msg ) ) return; } // Stores the initial bounding box to refresh the old area EDA_RECT bbox = module->GetBoundingBox(); m_Pcb->m_Status_Pcb = 0; GetBoard()->PadDelete( aPad ); // Update the bounding box module->CalculateBoundingBox(); // Refresh the modified screen area, using the initial bounding box // which is perhaps larger than the new bounding box m_canvas->RefreshDrawingRect( bbox ); OnModify(); }
/* Redraw the current graphic item during its creation * Use this function to show a new outline, in begin command */ static void ShowNewEdgeModule( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { BASE_SCREEN* screen = aPanel->GetScreen(); EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem(); if( edge == NULL ) return; MODULE* module = (MODULE*) edge->GetParent(); // if( erase ) { edge->Draw( aPanel, aDC, GR_XOR ); } edge->SetEnd( aPanel->GetParent()->GetCrossHairPosition() ); // Update relative coordinate. edge->SetEnd0( edge->GetEnd() - module->GetPosition() ); wxPoint pt( edge->GetEnd0() ); RotatePoint( &pt, -module->GetOrientation() ); edge->SetEnd0( pt ); edge->Draw( aPanel, aDC, GR_XOR ); module->CalculateBoundingBox(); }
void PCB_BASE_FRAME::DeletePad( D_PAD* aPad, bool aQuery ) { if( aPad == NULL ) return; MODULE* module = (MODULE*) aPad->GetParent(); module->SetLastEditTime(); // aQuery = true to prompt for confirmation, false to delete silently if( aQuery ) { wxString msg; msg.Printf( _( "Delete Pad (footprint %s %s) ?" ), GetChars( module->GetReference() ), GetChars( module->GetValue() ) ); if( !IsOK( this, msg ) ) return; } m_Pcb->m_Status_Pcb = 0; aPad->DeleteStructure(); // Refresh the modified screen area, using the initial bounding box // which is perhaps larger than the new bounding box m_canvas->RefreshDrawingRect( module->GetBoundingBox() ); // Update the bounding box module->CalculateBoundingBox(); OnModify(); }
/* abort function in moving outline. */ static void Abort_Move_ModuleOutline( EDA_DRAW_PANEL* Panel, wxDC* DC ) { EDGE_MODULE* edge = (EDGE_MODULE*) Panel->GetScreen()->GetCurItem(); Panel->SetMouseCapture( NULL, NULL ); if( edge && ( edge->Type() == PCB_MODULE_EDGE_T ) ) { if( edge->IsNew() ) // On aborting, delete new outline. { MODULE* module = (MODULE*) edge->GetParent(); edge->Draw( Panel, DC, GR_XOR, MoveVector ); edge->DeleteStructure(); module->CalculateBoundingBox(); } else // On aborting, move existing outline to its initial position. { edge->Draw( Panel, DC, GR_XOR, MoveVector ); edge->ClearFlags(); edge->Draw( Panel, DC, GR_OR ); } } Panel->GetScreen()->SetCurItem( NULL ); }
void FOOTPRINT_EDIT_FRAME::Edit_Edge_Layer( EDGE_MODULE* aEdge ) { // note: if aEdge == NULL, all outline segments will be modified MODULE* module = GetBoard()->m_Modules; PCB_LAYER_ID layer = F_SilkS; bool modified = false; if( aEdge ) layer = aEdge->GetLayer(); // Ask for the new layer PCB_LAYER_ID new_layer = SelectLayer( layer, Edge_Cuts ); if( layer < 0 ) return; if( IsCopperLayer( new_layer ) ) { // an edge is put on a copper layer, and it is very dangerous. // A confirmation is requested if( !IsOK( this, _( "The graphic item will be on a copper layer.\n" "This is very dangerous. Are you sure?" ) ) ) return; } if( !aEdge ) { for( BOARD_ITEM *item = module->GraphicalItemsList() ; item != NULL; item = item->Next() ) { aEdge = dyn_cast<EDGE_MODULE*>( item ); if( aEdge && (aEdge->GetLayer() != new_layer) ) { if( ! modified ) // save only once SaveCopyInUndoList( module, UR_CHANGED ); aEdge->SetLayer( new_layer ); modified = true; } } } else if( aEdge->GetLayer() != new_layer ) { SaveCopyInUndoList( module, UR_CHANGED ); aEdge->SetLayer( new_layer ); modified = true; } if( modified ) { module->CalculateBoundingBox(); module->SetLastEditTime(); } }
void FOOTPRINT_EDIT_FRAME::Edit_Edge_Layer( EDGE_MODULE* aEdge ) { MODULE* module = GetBoard()->m_Modules; int new_layer = SILKSCREEN_N_FRONT; if( aEdge ) new_layer = aEdge->GetLayer(); // Ask for the new layer new_layer = SelectLayer( new_layer, FIRST_COPPER_LAYER, ECO2_N ); if( new_layer < 0 ) return; if( IsValidCopperLayerIndex( new_layer ) ) { /* an edge is put on a copper layer, and it is very dangerous. a *confirmation is requested */ if( !IsOK( this, _( "The graphic item will be on a copper layer. This is very dangerous. Are you sure?" ) ) ) return; } SaveCopyInUndoList( module, UR_MODEDIT ); if( aEdge == NULL ) { aEdge = (EDGE_MODULE*) (BOARD_ITEM*) module->m_Drawings; for( ; aEdge != NULL; aEdge = aEdge->Next() ) { if( aEdge->Type() != PCB_MODULE_EDGE_T ) continue; aEdge->SetLayer( new_layer ); } } else { aEdge->SetLayer( new_layer ); } OnModify(); module->CalculateBoundingBox(); module->m_LastEdit_Time = time( NULL ); }
void FOOTPRINT_EDIT_FRAME::Place_EdgeMod( EDGE_MODULE* aEdge ) { if( aEdge == NULL ) return; aEdge->Move( -MoveVector ); aEdge->ClearFlags(); m_canvas->SetMouseCapture( NULL, NULL ); SetCurItem( NULL ); OnModify(); MODULE* module = (MODULE*) aEdge->GetParent(); module->CalculateBoundingBox(); m_canvas->Refresh( ); }
void FOOTPRINT_EDIT_FRAME::End_Edge_Module( EDGE_MODULE* aEdge ) { MODULE* module = GetBoard()->m_Modules; if( aEdge ) { aEdge->ClearFlags(); // If last segment length is 0: remove it if( aEdge->GetStart() == aEdge->GetEnd() ) aEdge->DeleteStructure(); } module->CalculateBoundingBox(); module->SetLastEditTime(); OnModify(); m_canvas->SetMouseCapture( NULL, NULL ); }
void FOOTPRINT_EDIT_FRAME::Delete_Edge_Module( EDGE_MODULE* aEdge ) { if( aEdge == NULL ) return; if( aEdge->Type() != PCB_MODULE_EDGE_T ) { wxLogDebug( wxT( "StructType error: PCB_MODULE_EDGE_T expected" ) ); return; } MODULE* module = (MODULE*) aEdge->GetParent(); // Delete segment. aEdge->DeleteStructure(); module->SetLastEditTime(); module->CalculateBoundingBox(); OnModify(); }
void FOOTPRINT_EDIT_FRAME::Enter_Edge_Width( EDGE_MODULE* aEdge ) { wxString buffer; buffer = StringFromValue( g_UserUnit, GetDesignSettings().m_ModuleSegmentWidth ); wxTextEntryDialog dlg( this, _( "New Width:" ), _( "Edge Width" ), buffer ); if( dlg.ShowModal() != wxID_OK ) return; // canceled by user buffer = dlg.GetValue( ); GetDesignSettings().m_ModuleSegmentWidth = ValueFromString( g_UserUnit, buffer ); if( aEdge ) { MODULE* module = GetBoard()->m_Modules; aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth ); module->CalculateBoundingBox(); OnModify(); } }
/* Redraw the current moved graphic item when mouse is moving * Use this function to show an existing outline, in move command */ static void ShowCurrentOutlineWhileMoving( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { BASE_SCREEN* screen = aPanel->GetScreen(); EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem(); if( edge == NULL ) return; MODULE* module = (MODULE*) edge->GetParent(); if( aErase ) { edge->Draw( aPanel, aDC, GR_XOR, MoveVector ); } MoveVector = -(aPanel->GetParent()->GetCrossHairPosition() - CursorInitialPosition); edge->Draw( aPanel, aDC, GR_XOR, MoveVector ); module->CalculateBoundingBox(); }
// Rotate selected pad 90 degrees. void PCB_BASE_FRAME::RotatePad( D_PAD* aPad, wxDC* DC ) { if( aPad == NULL ) return; MODULE* module = aPad->GetParent(); module->SetLastEditTime(); OnModify(); if( DC ) module->Draw( m_canvas, DC, GR_XOR ); wxSize sz = aPad->GetSize(); EXCHG( sz.x, sz.y ); aPad->SetSize( sz ); sz = aPad->GetDrillSize(); EXCHG( sz.x, sz.y ); aPad->SetDrillSize( sz ); wxPoint pt = aPad->GetOffset(); EXCHG( pt.x, pt.y ); aPad->SetOffset( pt ); aPad->SetOffset( wxPoint( aPad->GetOffset().x, -aPad->GetOffset().y ) ); sz = aPad->GetDelta(); EXCHG( sz.x, sz.y ); sz.x = -sz.x; aPad->SetDelta( sz ); module->CalculateBoundingBox(); SetMsgPanel( aPad ); if( DC ) module->Draw( m_canvas, DC, GR_OR ); }
bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() { if( !wxDialog::TransferDataFromWindow() ) return false; if( !m_panelGeneral->TransferDataFromWindow() ) return false; if( !m_localSettingsPanel->TransferDataFromWindow() ) return false; if( !padValuesOK() ) return false; bool rastnestIsChanged = false; int isign = m_isFlipped ? -1 : 1; transferDataToPad( m_padMaster ); // m_padMaster is a pattern: ensure there is no net for this pad: m_padMaster->SetNetCode( NETINFO_LIST::UNCONNECTED ); if( m_currentPad ) // Set current Pad parameters { wxSize size; MODULE* footprint = m_currentPad->GetParent(); m_parent->SaveCopyInUndoList( footprint, UR_CHANGED ); footprint->SetLastEditTime(); // redraw the area where the pad was, without pad (delete pad on screen) m_currentPad->SetFlags( DO_NOT_DRAW ); m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); m_currentPad->ClearFlags( DO_NOT_DRAW ); // Update values m_currentPad->SetShape( m_padMaster->GetShape() ); m_currentPad->SetAttribute( m_padMaster->GetAttribute() ); if( m_currentPad->GetPosition() != m_padMaster->GetPosition() ) { m_currentPad->SetPosition( m_padMaster->GetPosition() ); rastnestIsChanged = true; } // compute the pos 0 value, i.e. pad position for footprint with orientation = 0 // i.e. relative to footprint origin (footprint position) wxPoint pt = m_currentPad->GetPosition() - footprint->GetPosition(); RotatePoint( &pt, -footprint->GetOrientation() ); m_currentPad->SetPos0( pt ); m_currentPad->SetOrientation( m_padMaster->GetOrientation() * isign + footprint->GetOrientation() ); m_currentPad->SetSize( m_padMaster->GetSize() ); size = m_padMaster->GetDelta(); size.y *= isign; m_currentPad->SetDelta( size ); m_currentPad->SetDrillSize( m_padMaster->GetDrillSize() ); m_currentPad->SetDrillShape( m_padMaster->GetDrillShape() ); wxPoint offset = m_padMaster->GetOffset(); offset.y *= isign; m_currentPad->SetOffset( offset ); m_currentPad->SetPadToDieLength( m_padMaster->GetPadToDieLength() ); if( m_currentPad->GetLayerSet() != m_padMaster->GetLayerSet() ) { rastnestIsChanged = true; m_currentPad->SetLayerSet( m_padMaster->GetLayerSet() ); } if( m_isFlipped ) { m_currentPad->SetLayerSet( FlipLayerMask( m_currentPad->GetLayerSet() ) ); } m_currentPad->SetPadName( m_padMaster->GetPadName() ); wxString padNetname; // For PAD_ATTRIB_HOLE_NOT_PLATED, ensure there is no net name selected if( m_padMaster->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED ) padNetname = m_PadNetNameCtrl->GetValue(); if( m_currentPad->GetNetname() != padNetname ) { const NETINFO_ITEM* netinfo = m_board->FindNet( padNetname ); if( !padNetname.IsEmpty() && netinfo == NULL ) { DisplayError( NULL, _( "Unknown netname, netname not changed" ) ); } else if( netinfo ) { rastnestIsChanged = true; m_currentPad->SetNetCode( netinfo->GetNet() ); } } m_currentPad->SetLocalClearance( m_padMaster->GetLocalClearance() ); m_currentPad->SetLocalSolderMaskMargin( m_padMaster->GetLocalSolderMaskMargin() ); m_currentPad->SetLocalSolderPasteMargin( m_padMaster->GetLocalSolderPasteMargin() ); m_currentPad->SetLocalSolderPasteMarginRatio( m_padMaster->GetLocalSolderPasteMarginRatio() ); m_currentPad->SetZoneConnection( m_padMaster->GetZoneConnection() ); m_currentPad->SetThermalWidth( m_padMaster->GetThermalWidth() ); m_currentPad->SetThermalGap( m_padMaster->GetThermalGap() ); m_currentPad->SetRoundRectRadiusRatio( m_padMaster->GetRoundRectRadiusRatio() ); // rounded rect pads with radius ratio = 0 are in fact rect pads. // So set the right shape (and perhaps issues with a radius = 0) if( m_currentPad->GetShape() == PAD_SHAPE_ROUNDRECT && m_currentPad->GetRoundRectRadiusRatio() == 0.0 ) { m_currentPad->SetShape( PAD_SHAPE_RECT ); } footprint->CalculateBoundingBox(); m_parent->SetMsgPanel( m_currentPad ); // redraw the area where the pad was m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); m_parent->OnModify(); } if( rastnestIsChanged ) // The net ratsnest must be recalculated m_board->m_Status_Pcb = 0; return true; }
void DIALOG_PAD_PROPERTIES::PadPropertiesAccept( wxCommandEvent& event ) { if( !padValuesOK() ) return; bool rastnestIsChanged = false; int isign = m_isFlipped ? -1 : 1; transferDataToPad( m_padMaster ); // m_padMaster is a pattern: ensure there is no net for this pad: m_padMaster->SetNetCode( NETINFO_LIST::UNCONNECTED ); if( m_currentPad ) // Set current Pad parameters { wxSize size; MODULE* module = m_currentPad->GetParent(); m_parent->SaveCopyInUndoList( module, UR_CHANGED ); module->SetLastEditTime(); // redraw the area where the pad was, without pad (delete pad on screen) m_currentPad->SetFlags( DO_NOT_DRAW ); m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); m_currentPad->ClearFlags( DO_NOT_DRAW ); // Update values m_currentPad->SetShape( m_padMaster->GetShape() ); m_currentPad->SetAttribute( m_padMaster->GetAttribute() ); if( m_currentPad->GetPosition() != m_padMaster->GetPosition() ) { m_currentPad->SetPosition( m_padMaster->GetPosition() ); rastnestIsChanged = true; } // compute the pos 0 value, i.e. pad position for module with orientation = 0 // i.e. relative to module origin (module position) wxPoint pt = m_currentPad->GetPosition() - module->GetPosition(); RotatePoint( &pt, -module->GetOrientation() ); m_currentPad->SetPos0( pt ); m_currentPad->SetOrientation( m_padMaster->GetOrientation() * isign + module->GetOrientation() ); m_currentPad->SetSize( m_padMaster->GetSize() ); size = m_padMaster->GetDelta(); size.y *= isign; m_currentPad->SetDelta( size ); m_currentPad->SetDrillSize( m_padMaster->GetDrillSize() ); m_currentPad->SetDrillShape( m_padMaster->GetDrillShape() ); wxPoint offset = m_padMaster->GetOffset(); offset.y *= isign; m_currentPad->SetOffset( offset ); m_currentPad->SetPadToDieLength( m_padMaster->GetPadToDieLength() ); if( m_currentPad->GetLayerSet() != m_padMaster->GetLayerSet() ) { rastnestIsChanged = true; m_currentPad->SetLayerSet( m_padMaster->GetLayerSet() ); } if( m_isFlipped ) m_currentPad->SetLayerSet( FlipLayerMask( m_currentPad->GetLayerSet() ) ); m_currentPad->SetPadName( m_padMaster->GetPadName() ); wxString padNetname; // For PAD_HOLE_NOT_PLATED, ensure there is no net name selected if( m_padMaster->GetAttribute() != PAD_HOLE_NOT_PLATED ) padNetname = m_PadNetNameCtrl->GetValue(); if( m_currentPad->GetNetname() != padNetname ) { const NETINFO_ITEM* netinfo = m_board->FindNet( padNetname ); if( !padNetname.IsEmpty() && netinfo == NULL ) { DisplayError( NULL, _( "Unknown netname, netname not changed" ) ); } else { rastnestIsChanged = true; m_currentPad->SetNetCode( netinfo->GetNet() ); } } m_currentPad->SetLocalClearance( m_padMaster->GetLocalClearance() ); m_currentPad->SetLocalSolderMaskMargin( m_padMaster->GetLocalSolderMaskMargin() ); m_currentPad->SetLocalSolderPasteMargin( m_padMaster->GetLocalSolderPasteMargin() ); m_currentPad->SetLocalSolderPasteMarginRatio( m_padMaster->GetLocalSolderPasteMarginRatio() ); m_currentPad->SetZoneConnection( m_padMaster->GetZoneConnection() ); m_currentPad->SetThermalWidth( m_padMaster->GetThermalWidth() ); m_currentPad->SetThermalGap( m_padMaster->GetThermalGap() ); module->CalculateBoundingBox(); m_parent->SetMsgPanel( m_currentPad ); // redraw the area where the pad was m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); m_parent->OnModify(); } EndModal( wxID_OK ); if( rastnestIsChanged ) // The net ratsnest must be recalculated m_board->m_Status_Pcb = 0; }
/* * Function GlobalChange_PadSettings * Function to change pad caracteristics for the given footprint * or alls footprints which look like the given footprint * aPad is the pattern. The given footprint is the parent of this pad * aSameFootprints: if true, make changes on all identical footprints * aPadShapeFilter: if true, make changes only on pads having the same shape as aPad * aPadOrientFilter: if true, make changes only on pads having the same orientation as aPad * aPadLayerFilter: if true, make changes only on pads having the same layers as aPad * aRedraw: if true: redraws the footprint * aSaveForUndo: if true: create an entry in the Undo/Redo list * (usually: true in Schematic editor, false in Module editor) */ void PCB_BASE_FRAME::GlobalChange_PadSettings( D_PAD* aPad, bool aSameFootprints, bool aPadShapeFilter, bool aPadOrientFilter, bool aPadLayerFilter, bool aRedraw, bool aSaveForUndo ) { if( aPad == NULL ) aPad = &GetDesignSettings().m_Pad_Master; MODULE* module = aPad->GetParent(); if( module == NULL ) { DisplayError( this, wxT( "Global_Import_Pad_Settings() Error: NULL module" ) ); return; } // Search and copy the name of library reference. MODULE* Module_Ref = module; double pad_orient = aPad->GetOrientation() - Module_Ref->GetOrientation(); // Prepare an undo list: if( aSaveForUndo ) { PICKED_ITEMS_LIST itemsList; for( module = m_Pcb->m_Modules; module; module = module->Next() ) { if( !aSameFootprints && (module != Module_Ref) ) continue; if( module->GetFPID() != Module_Ref->GetFPID() ) continue; bool saveMe = false; for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) { // Filters changes prohibited. if( aPadShapeFilter && ( pad->GetShape() != aPad->GetShape() ) ) continue; double currpad_orient = pad->GetOrientation() - module->GetOrientation(); if( aPadOrientFilter && ( currpad_orient != pad_orient ) ) continue; if( aPadLayerFilter && pad->GetLayerSet() != aPad->GetLayerSet() ) continue; saveMe = true; } if( saveMe ) { ITEM_PICKER itemWrapper( module, UR_CHANGED ); itemsList.PushItem( itemWrapper ); } } SaveCopyInUndoList( itemsList, UR_CHANGED ); } // Update the current module and same others modules if requested. for( module = m_Pcb->m_Modules; module; module = module->Next() ) { if( !aSameFootprints && (module != Module_Ref) ) continue; if( module->GetFPID() != Module_Ref->GetFPID() ) continue; // Erase module on screen if( aRedraw ) { module->SetFlags( DO_NOT_DRAW ); m_canvas->RefreshDrawingRect( module->GetBoundingBox() ); module->ClearFlags( DO_NOT_DRAW ); } for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) { // Filters changes prohibited. if( aPadShapeFilter && ( pad->GetShape() != aPad->GetShape() ) ) continue; if( aPadOrientFilter && (pad->GetOrientation() - module->GetOrientation()) != pad_orient ) continue; if( aPadLayerFilter ) { if( pad->GetLayerSet() != aPad->GetLayerSet() ) continue; else m_Pcb->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK); } // Change characteristics: pad->SetAttribute( aPad->GetAttribute() ); pad->SetShape( aPad->GetShape() ); pad->SetLayerSet( aPad->GetLayerSet() ); pad->SetSize( aPad->GetSize() ); pad->SetDelta( aPad->GetDelta() ); pad->SetOffset( aPad->GetOffset() ); pad->SetDrillSize( aPad->GetDrillSize() ); pad->SetDrillShape( aPad->GetDrillShape() ); pad->SetOrientation( pad_orient + module->GetOrientation() ); // copy also local mask margins, because these parameters usually depend on // pad sizes and layers pad->SetLocalSolderMaskMargin( aPad->GetLocalSolderMaskMargin() ); pad->SetLocalSolderPasteMargin( aPad->GetLocalSolderPasteMargin() ); pad->SetLocalSolderPasteMarginRatio( aPad->GetLocalSolderPasteMarginRatio() ); if( pad->GetShape() != PAD_TRAPEZOID ) { pad->SetDelta( wxSize( 0, 0 ) ); } if( pad->GetShape() == PAD_CIRCLE ) { // Ensure pad size.y = pad size.x int size = pad->GetSize().x; pad->SetSize( wxSize( size, size ) ); } switch( pad->GetAttribute() ) { case PAD_SMD: case PAD_CONN: pad->SetDrillSize( wxSize( 0, 0 ) ); pad->SetOffset( wxPoint( 0, 0 ) ); break; default: break; } } module->CalculateBoundingBox(); if( aRedraw ) m_canvas->RefreshDrawingRect( module->GetBoundingBox() ); } OnModify(); }
EDGE_MODULE* FOOTPRINT_EDIT_FRAME::Begin_Edge_Module( EDGE_MODULE* aEdge, wxDC* DC, STROKE_T type_edge ) { MODULE* module = GetBoard()->m_Modules; if( module == NULL ) return NULL; if( aEdge == NULL ) // Start a new edge item { SaveCopyInUndoList( module, UR_CHANGED ); aEdge = new EDGE_MODULE( module ); MoveVector.x = MoveVector.y = 0; // Add the new item to the Drawings list head module->GraphicalItemsList().PushFront( aEdge ); // Update characteristics of the segment or arc. aEdge->SetFlags( IS_NEW ); aEdge->SetAngle( 0 ); aEdge->SetShape( type_edge ); if( aEdge->GetShape() == S_ARC ) aEdge->SetAngle( ArcValue ); aEdge->SetWidth( GetDesignSettings().GetLineThickness( GetActiveLayer() ) ); aEdge->SetLayer( GetActiveLayer() ); // Initialize the starting point of the new segment or arc aEdge->SetStart( GetCrossHairPosition() ); // Initialize the ending point of the new segment or arc aEdge->SetEnd( aEdge->GetStart() ); // Initialize the relative coordinates aEdge->SetStart0( aEdge->GetStart() - module->GetPosition() ); RotatePoint( &aEdge->m_Start0, -module->GetOrientation() ); aEdge->m_End0 = aEdge->m_Start0; module->CalculateBoundingBox(); m_canvas->SetMouseCapture( ShowNewEdgeModule, Abort_Move_ModuleOutline ); } /* Segment creation in progress. * The ending coordinate is updated by the function * ShowNewEdgeModule() called on move mouse event * during the segment creation */ else { if( type_edge == S_SEGMENT ) { if( aEdge->m_Start0 != aEdge->m_End0 ) { aEdge->Draw( m_canvas, DC, GR_OR ); EDGE_MODULE* newedge = new EDGE_MODULE( *aEdge ); // insert _after_ aEdge, which is the same as inserting before aEdge->Next() module->GraphicalItemsList().Insert( newedge, aEdge->Next() ); aEdge->ClearFlags(); aEdge = newedge; // point now new item aEdge->SetFlags( IS_NEW ); aEdge->SetWidth( GetDesignSettings().GetLineThickness( aEdge->GetLayer() ) ); aEdge->SetStart( GetCrossHairPosition() ); aEdge->SetEnd( aEdge->GetStart() ); // Update relative coordinate. aEdge->SetStart0( aEdge->GetStart() - module->GetPosition() ); wxPoint pt( aEdge->GetStart0() ); RotatePoint( &pt, -module->GetOrientation() ); aEdge->SetStart0( pt ); aEdge->SetEnd0( aEdge->GetStart0() ); module->CalculateBoundingBox(); module->SetLastEditTime(); OnModify(); } } else { wxLogDebug( wxT( "Begin_Edge() error" ) ); } } return aEdge; }
// Routine to place a moved pad. void PCB_BASE_FRAME::PlacePad( D_PAD* aPad, wxDC* DC ) { int dX, dY; TRACK* Track; if( aPad == NULL ) return; MODULE* module = aPad->GetParent(); ITEM_PICKER picker( NULL, UR_CHANGED ); PICKED_ITEMS_LIST pickList; // Save dragged track segments in undo list for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ ) { Track = g_DragSegmentList[ii].m_Track; // Set the old state if( g_DragSegmentList[ii].m_Pad_Start ) Track->SetStart( Pad_OldPos ); if( g_DragSegmentList[ii].m_Pad_End ) Track->SetEnd( Pad_OldPos ); picker.SetItem( Track ); pickList.PushItem( picker ); } // Save old module and old items values wxPoint pad_curr_position = aPad->GetPosition(); aPad->SetPosition( Pad_OldPos ); if( g_DragSegmentList.size() == 0 ) SaveCopyInUndoList( module, UR_CHANGED ); else { picker.SetItem( module ); pickList.PushItem( picker ); SaveCopyInUndoList( pickList, UR_CHANGED ); } aPad->SetPosition( pad_curr_position ); aPad->Draw( m_canvas, DC, GR_XOR ); // Redraw dragged track segments for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ ) { Track = g_DragSegmentList[ii].m_Track; // Set the new state if( g_DragSegmentList[ii].m_Pad_Start ) Track->SetStart( aPad->GetPosition() ); if( g_DragSegmentList[ii].m_Pad_End ) Track->SetEnd( aPad->GetPosition() ); Track->SetState( IN_EDIT, OFF ); if( DC ) Track->Draw( m_canvas, DC, GR_OR ); } // Compute local coordinates (i.e refer to module position and for module orient = 0) dX = aPad->GetPosition().x - Pad_OldPos.x; dY = aPad->GetPosition().y - Pad_OldPos.y; RotatePoint( &dX, &dY, -module->GetOrientation() ); aPad->SetX0( dX + aPad->GetPos0().x ); aPad->SetY0( dY + aPad->GetPos0().y ); aPad->ClearFlags(); if( DC ) aPad->Draw( m_canvas, DC, GR_OR ); module->CalculateBoundingBox(); module->SetLastEditTime(); EraseDragList(); OnModify(); m_canvas->SetMouseCapture( NULL, NULL ); m_Pcb->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK ); }
MODULE* MWAVE::CreateMicrowaveInductor( INDUCTOR_PATTERN& inductorPattern, PCB_EDIT_FRAME* aPcbFrame, wxString& aErrorMessage ) { /* Build a microwave inductor footprint. * - Length Mself.lng * - Extremities Mself.m_Start and Mself.m_End * We must determine: * Mself.nbrin = number of segments perpendicular to the direction * (The coil nbrin will demicercles + 1 + 2 1 / 4 circle) * Mself.lbrin = length of a strand * Mself.radius = radius of rounded parts of the coil * Mself.delta = segments extremities connection between him and the coil even * * The equations are * Mself.m_Size.x = 2 * Mself.radius + Mself.lbrin * Mself.m_Size.y * Mself.delta = 2 + 2 * Mself.nbrin * Mself.radius * Mself.lng = 2 * Mself.delta / / connections to the coil + (Mself.nbrin-2) * Mself.lbrin / / length of the strands except 1st and last + (Mself.nbrin 1) * (PI * Mself.radius) / / length of rounded * Mself.lbrin + / 2 - Melf.radius * 2) / / length of 1st and last bit * * The constraints are: * Nbrin >= 2 * Mself.radius < Mself.m_Size.x * Mself.m_Size.y = Mself.radius * 4 + 2 * Mself.raccord * Mself.lbrin> Mself.radius * 2 * * The calculation is conducted in the following way: * Initially: * Nbrin = 2 * Radius = 4 * m_Size.x (arbitrarily fixed value) * Then: * Increasing the number of segments to the desired length * (Radius decreases if necessary) */ D_PAD* pad; int ll; wxString msg; auto pt = inductorPattern.m_End - inductorPattern.m_Start; int min_len = KiROUND( EuclideanNorm( pt ) ); inductorPattern.m_length = min_len; // Enter the desired length. msg = StringFromValue( g_UserUnit, inductorPattern.m_length ); wxTextEntryDialog dlg( nullptr, wxEmptyString, _( "Length of Trace:" ), msg ); if( dlg.ShowModal() != wxID_OK ) return nullptr; // canceled by user msg = dlg.GetValue(); inductorPattern.m_length = ValueFromString( g_UserUnit, msg ); // Control values (ii = minimum length) if( inductorPattern.m_length < min_len ) { aErrorMessage = _( "Requested length < minimum length" ); return nullptr; } // Calculate the elements. std::vector <wxPoint> buffer; ll = BuildCornersList_S_Shape( buffer, inductorPattern.m_Start, inductorPattern.m_End, inductorPattern.m_length, inductorPattern.m_Width ); if( !ll ) { aErrorMessage = _( "Requested length too large" ); return nullptr; } // Generate footprint. the value is also used as footprint name. msg = "L"; wxTextEntryDialog cmpdlg( nullptr, wxEmptyString, _( "Component Value:" ), msg ); cmpdlg.SetTextValidator( FILE_NAME_CHAR_VALIDATOR( &msg ) ); if( ( cmpdlg.ShowModal() != wxID_OK ) || msg.IsEmpty() ) return nullptr; // Aborted by user MODULE* module = aPcbFrame->CreateNewModule( msg ); // here the module is already in the BOARD, CreateNewModule() does that. module->SetFPID( LIB_ID( wxString( "mw_inductor" ) ) ); module->SetAttributes( MOD_VIRTUAL | MOD_CMS ); module->ClearFlags(); module->SetPosition( inductorPattern.m_End ); // Generate segments for( unsigned jj = 1; jj < buffer.size(); jj++ ) { EDGE_MODULE* PtSegm; PtSegm = new EDGE_MODULE( module ); PtSegm->SetStart( buffer[jj - 1] ); PtSegm->SetEnd( buffer[jj] ); PtSegm->SetWidth( inductorPattern.m_Width ); PtSegm->SetLayer( module->GetLayer() ); PtSegm->SetShape( S_SEGMENT ); PtSegm->SetStart0( PtSegm->GetStart() - module->GetPosition() ); PtSegm->SetEnd0( PtSegm->GetEnd() - module->GetPosition() ); module->GraphicalItemsList().PushBack( PtSegm ); } // Place a pad on each end of coil. pad = new D_PAD( module ); module->PadsList().PushFront( pad ); pad->SetName( "1" ); pad->SetPosition( inductorPattern.m_End ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); pad->SetSize( wxSize( inductorPattern.m_Width, inductorPattern.m_Width ) ); pad->SetLayerSet( LSET( module->GetLayer() ) ); pad->SetAttribute( PAD_ATTRIB_SMD ); pad->SetShape( PAD_SHAPE_CIRCLE ); D_PAD* newpad = new D_PAD( *pad ); module->PadsList().Insert( newpad, pad->Next() ); pad = newpad; pad->SetName( "2" ); pad->SetPosition( inductorPattern.m_Start ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); // Modify text positions. wxPoint refPos( ( inductorPattern.m_Start.x + inductorPattern.m_End.x ) / 2, ( inductorPattern.m_Start.y + inductorPattern.m_End.y ) / 2 ); wxPoint valPos = refPos; refPos.y -= module->Reference().GetTextSize().y; module->Reference().SetPosition( refPos ); valPos.y += module->Value().GetTextSize().y; module->Value().SetPosition( valPos ); module->CalculateBoundingBox(); return module; }
MODULE* PCB_EDIT_FRAME::Genere_Self( wxDC* DC ) { D_PAD* pad; int ll; wxString msg; m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); m_canvas->SetMouseCapture( NULL, NULL ); if( s_inductor_pattern.m_Flag == false ) { DisplayError( this, wxT( "Starting point not init.." ) ); return NULL; } s_inductor_pattern.m_Flag = false; s_inductor_pattern.m_End = GetCrossHairPosition(); wxPoint pt = s_inductor_pattern.m_End - s_inductor_pattern.m_Start; int min_len = KiROUND( EuclideanNorm( pt ) ); s_inductor_pattern.m_lenght = min_len; // Enter the desired length. msg = StringFromValue( g_UserUnit, s_inductor_pattern.m_lenght ); wxTextEntryDialog dlg( this, wxEmptyString, _( "Length of Trace:" ), msg ); if( dlg.ShowModal() != wxID_OK ) return NULL; // canceled by user msg = dlg.GetValue(); s_inductor_pattern.m_lenght = ValueFromString( g_UserUnit, msg ); // Control values (ii = minimum length) if( s_inductor_pattern.m_lenght < min_len ) { DisplayError( this, _( "Requested length < minimum length" ) ); return NULL; } // Calculate the elements. s_inductor_pattern.m_Width = GetDesignSettings().GetCurrentTrackWidth(); std::vector <wxPoint> buffer; ll = BuildCornersList_S_Shape( buffer, s_inductor_pattern.m_Start, s_inductor_pattern.m_End, s_inductor_pattern.m_lenght, s_inductor_pattern.m_Width ); if( !ll ) { DisplayError( this, _( "Requested length too large" ) ); return NULL; } // Generate footprint. the value is also used as footprint name. msg.Empty(); wxTextEntryDialog cmpdlg( this, wxEmptyString, _( "Component Value:" ), msg ); cmpdlg.SetTextValidator( FILE_NAME_CHAR_VALIDATOR( &msg ) ); if( ( cmpdlg.ShowModal() != wxID_OK ) || msg.IsEmpty() ) return NULL; // Aborted by user MODULE* module = CreateNewModule( msg ); // here the module is already in the BOARD, CreateNewModule() does that. module->SetFPID( FPID( std::string( "mw_inductor" ) ) ); module->SetAttributes( MOD_VIRTUAL | MOD_CMS ); module->ClearFlags(); module->SetPosition( s_inductor_pattern.m_End ); // Generate segments for( unsigned jj = 1; jj < buffer.size(); jj++ ) { EDGE_MODULE* PtSegm; PtSegm = new EDGE_MODULE( module ); PtSegm->SetStart( buffer[jj - 1] ); PtSegm->SetEnd( buffer[jj] ); PtSegm->SetWidth( s_inductor_pattern.m_Width ); PtSegm->SetLayer( module->GetLayer() ); PtSegm->SetShape( S_SEGMENT ); PtSegm->SetStart0( PtSegm->GetStart() - module->GetPosition() ); PtSegm->SetEnd0( PtSegm->GetEnd() - module->GetPosition() ); module->GraphicalItems().PushBack( PtSegm ); } // Place a pad on each end of coil. pad = new D_PAD( module ); module->Pads().PushFront( pad ); pad->SetPadName( wxT( "1" ) ); pad->SetPosition( s_inductor_pattern.m_End ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); pad->SetSize( wxSize( s_inductor_pattern.m_Width, s_inductor_pattern.m_Width ) ); pad->SetLayerSet( LSET( module->GetLayer() ) ); pad->SetAttribute( PAD_ATTRIB_SMD ); pad->SetShape( PAD_SHAPE_CIRCLE ); D_PAD* newpad = new D_PAD( *pad ); module->Pads().Insert( newpad, pad->Next() ); pad = newpad; pad->SetPadName( wxT( "2" ) ); pad->SetPosition( s_inductor_pattern.m_Start ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); // Modify text positions. SetMsgPanel( module ); wxPoint refPos( ( s_inductor_pattern.m_Start.x + s_inductor_pattern.m_End.x ) / 2, ( s_inductor_pattern.m_Start.y + s_inductor_pattern.m_End.y ) / 2 ); wxPoint valPos = refPos; refPos.y -= module->Reference().GetSize().y; module->Reference().SetPosition( refPos ); valPos.y += module->Value().GetSize().y; module->Value().SetPosition( valPos ); module->CalculateBoundingBox(); module->Draw( m_canvas, DC, GR_OR ); return module; }
/* * Function DoPushPadProperties * Function to change pad properties for the given footprint or all identical footprints * aPad is the pattern. The given footprint is the parent of this pad * aSameFootprints: if true, make changes on all identical footprints * aPadShapeFilter: if true, make changes only on pads having the same shape as aPad * aPadOrientFilter: if true, make changes only on pads having the same orientation as aPad * aPadLayerFilter: if true, make changes only on pads having the same layers as aPad * aSaveForUndo: if true: create an entry in the Undo/Redo list * (usually: true in Schematic editor, false in Module editor) */ void PCB_BASE_FRAME::DoPushPadProperties( D_PAD* aPad, bool aSameFootprints, bool aPadShapeFilter, bool aPadOrientFilter, bool aPadLayerFilter, bool aSaveForUndo ) { MODULE* Module_Ref = aPad->GetParent(); double pad_orient = aPad->GetOrientation() - Module_Ref->GetOrientation(); // Prepare an undo list: if( aSaveForUndo ) { PICKED_ITEMS_LIST itemsList; if( aSameFootprints ) { for( MODULE* module = m_Pcb->m_Modules; module; module = module->Next() ) { if( module->GetFPID() == Module_Ref->GetFPID() ) { ITEM_PICKER itemWrapper( module, UR_CHANGED ); itemsList.PushItem( itemWrapper ); } } } else { ITEM_PICKER itemWrapper( Module_Ref, UR_CHANGED ); itemsList.PushItem( itemWrapper ); } SaveCopyInUndoList( itemsList, UR_CHANGED ); } // Update the current module and same others modules if requested. for( MODULE* module = m_Pcb->m_Modules; module; module = module->Next() ) { if( !aSameFootprints && (module != Module_Ref) ) continue; if( module->GetFPID() != Module_Ref->GetFPID() ) continue; // Erase module on screen module->SetFlags( DO_NOT_DRAW ); m_canvas->RefreshDrawingRect( module->GetBoundingBox() ); module->ClearFlags( DO_NOT_DRAW ); for( D_PAD* pad = module->PadsList(); pad; pad = pad->Next() ) { if( aPadShapeFilter && ( pad->GetShape() != aPad->GetShape() ) ) continue; double currpad_orient = pad->GetOrientation() - module->GetOrientation(); if( aPadOrientFilter && ( currpad_orient != pad_orient ) ) continue; if( aPadLayerFilter && ( pad->GetLayerSet() != aPad->GetLayerSet() ) ) continue; // Do not copy pad to itself, it can create issues with custom pad primitives. if( pad == aPad ) continue; pad->ImportSettingsFromMaster( *aPad ); } module->CalculateBoundingBox(); m_canvas->RefreshDrawingRect( module->GetBoundingBox() ); } OnModify(); }
MODULE* PCB_EDIT_FRAME::Create_MuWaveComponent( int shape_type ) { int oX; D_PAD* pad; MODULE* module; wxString msg, cmp_name; int pad_count = 2; int angle = 0; // Ref and value text size (O = use board default value. // will be set to a value depending on the footprint size, if possible int text_size = 0; // Enter the size of the gap or stub int gap_size = GetDesignSettings().GetCurrentTrackWidth(); switch( shape_type ) { case 0: msg = _( "Gap" ); cmp_name = wxT( "muwave_gap" ); text_size = gap_size; break; case 1: msg = _( "Stub" ); cmp_name = wxT( "muwave_stub" ); text_size = gap_size; pad_count = 2; break; case 2: msg = _( "Arc Stub" ); cmp_name = wxT( "muwave_arcstub" ); pad_count = 1; break; default: msg = wxT( "???" ); break; } wxString value = StringFromValue( g_UserUnit, gap_size ); wxTextEntryDialog dlg( this, msg, _( "Create microwave module" ), value ); if( dlg.ShowModal() != wxID_OK ) { m_canvas->MoveCursorToCrossHair(); return NULL; // cancelled by user } value = dlg.GetValue(); gap_size = ValueFromString( g_UserUnit, value ); bool abort = false; if( shape_type == 2 ) { double fcoeff = 10.0, fval; msg.Printf( wxT( "%3.1f" ), angle / fcoeff ); wxTextEntryDialog angledlg( this, _( "Angle in degrees:" ), _( "Create microwave module" ), msg ); if( angledlg.ShowModal() != wxID_OK ) { m_canvas->MoveCursorToCrossHair(); return NULL; // cancelled by user } msg = angledlg.GetValue(); if( !msg.ToDouble( &fval ) ) { DisplayError( this, _( "Incorrect number, abort" ) ); abort = true; } angle = std::abs( KiROUND( fval * fcoeff ) ); if( angle > 1800 ) angle = 1800; } if( abort ) { m_canvas->MoveCursorToCrossHair(); return NULL; } module = CreateMuWaveBaseFootprint( cmp_name, text_size, pad_count ); pad = module->Pads(); switch( shape_type ) { case 0: //Gap : oX = -( gap_size + pad->GetSize().x ) / 2; pad->SetX0( oX ); pad->SetX( pad->GetPos0().x + pad->GetPosition().x ); pad = pad->Next(); pad->SetX0( oX + gap_size + pad->GetSize().x ); pad->SetX( pad->GetPos0().x + pad->GetPosition().x ); break; case 1: //Stub : pad->SetPadName( wxT( "1" ) ); pad = pad->Next(); pad->SetY0( -( gap_size + pad->GetSize().y ) / 2 ); pad->SetSize( wxSize( pad->GetSize().x, gap_size ) ); pad->SetY( pad->GetPos0().y + pad->GetPosition().y ); break; case 2: // Arc Stub created by a polygonal approach: { EDGE_MODULE* edge = new EDGE_MODULE( module ); module->GraphicalItems().PushFront( edge ); edge->SetShape( S_POLYGON ); edge->SetLayer( F_Cu ); int numPoints = (angle / 50) + 3; // Note: angles are in 0.1 degrees std::vector<wxPoint>& polyPoints = edge->GetPolyPoints(); polyPoints.reserve( numPoints ); edge->m_Start0.y = -pad->GetSize().y / 2; polyPoints.push_back( wxPoint( 0, 0 ) ); int theta = -angle / 2; for( int ii = 1; ii<numPoints - 1; ii++ ) { wxPoint pt( 0, -gap_size ); RotatePoint( &pt.x, &pt.y, theta ); polyPoints.push_back( pt ); theta += 50; if( theta > angle / 2 ) theta = angle / 2; } // Close the polygon: polyPoints.push_back( polyPoints[0] ); } break; default: break; } module->CalculateBoundingBox(); GetBoard()->m_Status_Pcb = 0; OnModify(); return module; }
/* Function to move components in a rectangular area format 4 / 3, * starting from the mouse cursor * The components with the FIXED status set are not moved */ void PCB_EDIT_FRAME::SpreadFootprints( bool aFootprintsOutsideBoardOnly ) { EDA_RECT bbox = GetBoard()->ComputeBoundingBox( true ); bool edgesExist = ( bbox.GetWidth() || bbox.GetHeight() ); // no edges exist if( aFootprintsOutsideBoardOnly && !edgesExist ) { DisplayError( this, _( "Could not automatically place footprints. No board outlines detected." ) ); return; } // if aFootprintsOutsideBoardOnly is true, and if board outline exists, // wue have to filter footprints to move: bool outsideBrdFilter = aFootprintsOutsideBoardOnly && edgesExist; // Build candidate list // calculate also the area needed by these footprints MODULE* module = GetBoard()->m_Modules; std::vector <MODULE*> moduleList; for( ; module != NULL; module = module->Next() ) { module->CalculateBoundingBox(); if( outsideBrdFilter ) { if( bbox.Contains( module->GetPosition() ) ) continue; } if( module->IsLocked() ) continue; moduleList.push_back(module); } if( moduleList.size() == 0 ) // Nothing to do return; // sort footprints by sheet path. we group them later by sheet sort( moduleList.begin(), moduleList.end(), sortModulesbySheetPath ); // Undo command: init undo list PICKED_ITEMS_LIST undoList; undoList.m_Status = UR_CHANGED; ITEM_PICKER picker( NULL, UR_CHANGED ); for( unsigned ii = 0; ii < moduleList.size(); ii++ ) { module = moduleList[ii]; // Undo: add copy of module to undo list picker.SetItem( module ); picker.SetLink( module->Clone() ); undoList.PushItem( picker ); } // Extract and place footprints by sheet std::vector <MODULE*> moduleListBySheet; std::vector <EDA_RECT> placementSheetAreas; double subsurface; double placementsurface = 0.0; wxPoint placementAreaPosition = GetCrossHairPosition(); // We do not want to move footprints inside an existing board. // move the placement area position outside the board bounding box // to the left of the board if( edgesExist ) { if( placementAreaPosition.x < bbox.GetEnd().x && placementAreaPosition.y < bbox.GetEnd().y ) { placementAreaPosition.x = bbox.GetEnd().x; placementAreaPosition.y = bbox.GetOrigin().y; } } // The placement uses 2 passes: // the first pass creates the rectangular areas to place footprints // each sheet in schematic creates one rectangular area. // the second pass moves footprints inside these areas for( int pass = 0; pass < 2; pass++ ) { int subareaIdx = 0; moduleListBySheet.clear(); subsurface = 0.0; for( unsigned ii = 0; ii < moduleList.size(); ii++ ) { module = moduleList[ii]; bool islastItem = false; if( ii == moduleList.size() - 1 || ( moduleList[ii]->GetPath().BeforeLast( '/' ) != moduleList[ii+1]->GetPath().BeforeLast( '/' ) ) ) islastItem = true; moduleListBySheet.push_back( module ); subsurface += module->GetArea(); if( islastItem ) { // end of the footprint sublist relative to the same sheet path // calculate placement of the current sublist EDA_RECT freeArea; int Xsize_allowed = (int) ( sqrt( subsurface ) * 4.0 / 3.0 ); int Ysize_allowed = (int) ( subsurface / Xsize_allowed ); freeArea.SetWidth( Xsize_allowed ); freeArea.SetHeight( Ysize_allowed ); CRectPlacement placementArea; if( pass == 1 ) { wxPoint areapos = placementSheetAreas[subareaIdx].GetOrigin() + placementAreaPosition; freeArea.SetOrigin( areapos ); } bool findAreaOnly = pass == 0; moveFootprintsInArea( placementArea, moduleListBySheet, freeArea, findAreaOnly ); if( pass == 0 ) { // Populate sheet placement areas list EDA_RECT sub_area; sub_area.SetWidth( placementArea.GetW()*scale ); sub_area.SetHeight( placementArea.GetH()*scale ); // Add a margin around the sheet placement area: sub_area.Inflate( Millimeter2iu( 1.5 ) ); placementSheetAreas.push_back( sub_area ); placementsurface += (double) sub_area.GetWidth()* sub_area.GetHeight(); } // Prepare buffers for next sheet subsurface = 0.0; moduleListBySheet.clear(); subareaIdx++; } } // End of pass: // At the end of the first pass, we have to find position of each sheet // placement area if( pass == 0 ) { int Xsize_allowed = (int) ( sqrt( placementsurface ) * 4.0 / 3.0 ); int Ysize_allowed = (int) ( placementsurface / Xsize_allowed ); CRectPlacement placementArea; CSubRectArray vecSubRects; fillRectList( vecSubRects, placementSheetAreas ); spreadRectangles( placementArea, vecSubRects, Xsize_allowed, Ysize_allowed ); for( unsigned it = 0; it < vecSubRects.size(); ++it ) { TSubRect& srect = vecSubRects[it]; wxPoint pos( srect.x*scale, srect.y*scale ); wxSize size( srect.w*scale, srect.h*scale ); placementSheetAreas[srect.n].SetOrigin( pos ); placementSheetAreas[srect.n].SetSize( size ); } } } // End pass // Undo: commit list SaveCopyInUndoList( undoList, UR_CHANGED ); OnModify(); m_canvas->Refresh(); }
/** * Function PickModule * find the "best" module place * The criteria are: * - Maximum ratsnest with modules already placed * - Max size, and number of pads max */ static MODULE* PickModule( PCB_EDIT_FRAME* pcbframe, wxDC* DC ) { MODULE* Module; std::vector <MODULE*> moduleList; // Build sorted footprints list (sort by decreasing size ) Module = pcbframe->GetBoard()->m_Modules; for( ; Module != NULL; Module = Module->Next() ) { Module->CalculateBoundingBox(); moduleList.push_back( Module ); } sort( moduleList.begin(), moduleList.end(), Tri_PlaceModules ); for( unsigned ii = 0; ii < moduleList.size(); ii++ ) { Module = moduleList[ii]; Module->SetFlag( 0 ); if( !Module->NeedsPlaced() ) continue; pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK; pcbframe->SetMsgPanel( Module ); pcbframe->build_ratsnest_module( Module ); // Calculate external ratsnest. for( unsigned ii = 0; ii < pcbframe->GetBoard()->m_LocalRatsnest.size(); ii++ ) { if( ( pcbframe->GetBoard()->m_LocalRatsnest[ii].m_Status & LOCAL_RATSNEST_ITEM ) == 0 ) Module->IncrementFlag(); } } pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK; sort( moduleList.begin(), moduleList.end(), sortFootprintsByRatsnestSize ); // Search for "best" module. MODULE* bestModule = NULL; MODULE* altModule = NULL; for( unsigned ii = 0; ii < moduleList.size(); ii++ ) { Module = moduleList[ii]; if( !Module->NeedsPlaced() ) continue; altModule = Module; if( Module->GetFlag() == 0 ) continue; bestModule = Module; break; } if( bestModule ) return bestModule; else return altModule; }
MODULE* PCB_EDIT_FRAME::Genere_Self( wxDC* DC ) { D_PAD* pad; int ll; wxString msg; m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); m_canvas->SetMouseCapture( NULL, NULL ); if( Self_On == 0 ) { DisplayError( this, wxT( "Starting point not init.." ) ); return NULL; } Self_On = 0; Mself.m_End = GetCrossHairPosition(); wxPoint pt = Mself.m_End - Mself.m_Start; int min_len = KiROUND( EuclideanNorm( pt ) ); Mself.lng = min_len; // Enter the desired length. msg = StringFromValue( g_UserUnit, Mself.lng ); wxTextEntryDialog dlg( this, _( "Length:" ), _( "Length" ), msg ); if( dlg.ShowModal() != wxID_OK ) return NULL; // canceled by user msg = dlg.GetValue(); Mself.lng = ValueFromString( g_UserUnit, msg ); // Control values (ii = minimum length) if( Mself.lng < min_len ) { DisplayError( this, _( "Requested length < minimum length" ) ); return NULL; } // Calculate the elements. Mself.m_Width = GetBoard()->GetCurrentTrackWidth(); std::vector <wxPoint> buffer; ll = BuildCornersList_S_Shape( buffer, Mself.m_Start, Mself.m_End, Mself.lng, Mself.m_Width ); if( !ll ) { DisplayError( this, _( "Requested length too large" ) ); return NULL; } // Generate module. MODULE* module; module = Create_1_Module( wxEmptyString ); if( module == NULL ) return NULL; // here the module is already in the BOARD, Create_1_Module() does that. module->SetFPID( FPID( std::string( "MuSelf" ) ) ); module->SetAttributes( MOD_VIRTUAL | MOD_CMS ); module->ClearFlags(); module->SetPosition( Mself.m_End ); // Generate segments for( unsigned jj = 1; jj < buffer.size(); jj++ ) { EDGE_MODULE* PtSegm; PtSegm = new EDGE_MODULE( module ); PtSegm->SetStart( buffer[jj - 1] ); PtSegm->SetEnd( buffer[jj] ); PtSegm->SetWidth( Mself.m_Width ); PtSegm->SetLayer( module->GetLayer() ); PtSegm->SetShape( S_SEGMENT ); PtSegm->SetStart0( PtSegm->GetStart() - module->GetPosition() ); PtSegm->SetEnd0( PtSegm->GetEnd() - module->GetPosition() ); module->GraphicalItems().PushBack( PtSegm ); } // Place a pad on each end of coil. pad = new D_PAD( module ); module->Pads().PushFront( pad ); pad->SetPadName( wxT( "1" ) ); pad->SetPosition( Mself.m_End ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); pad->SetSize( wxSize( Mself.m_Width, Mself.m_Width ) ); pad->SetLayerMask( GetLayerMask( module->GetLayer() ) ); pad->SetAttribute( PAD_SMD ); pad->SetShape( PAD_CIRCLE ); D_PAD* newpad = new D_PAD( *pad ); module->Pads().Insert( newpad, pad->Next() ); pad = newpad; pad->SetPadName( wxT( "2" ) ); pad->SetPosition( Mself.m_Start ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); // Modify text positions. SetMsgPanel( module ); wxPoint refPos( ( Mself.m_Start.x + Mself.m_End.x ) / 2, ( Mself.m_Start.y + Mself.m_End.y ) / 2 ); wxPoint valPos = refPos; refPos.y -= module->Reference().GetSize().y; module->Reference().SetTextPosition( refPos ); valPos.y += module->Value().GetSize().y; module->Value().SetTextPosition( valPos ); module->Reference().SetPos0( module->Reference().GetTextPosition() - module->GetPosition() ); module->Value().SetPos0( module->Value().GetTextPosition() - module->GetPosition() ); module->CalculateBoundingBox(); module->Draw( m_canvas, DC, GR_OR ); return module; }