//* Plot a graphic item (outline) relative to a footprint void BRDITEMS_PLOTTER::Plot_1_EdgeModule( EDGE_MODULE* aEdge ) { int type_trace; // Type of item to plot. int thickness; // Segment thickness. int radius; // Circle radius. if( aEdge->Type() != PCB_MODULE_EDGE_T ) return; m_plotter->SetColor( getColor( aEdge->GetLayer() ) ); type_trace = aEdge->GetShape(); thickness = aEdge->GetWidth(); wxPoint pos( aEdge->GetStart() ); wxPoint end( aEdge->GetEnd() ); switch( type_trace ) { case S_SEGMENT: m_plotter->ThickSegment( pos, end, thickness, GetMode() ); break; case S_CIRCLE: radius = KiROUND( GetLineLength( end, pos ) ); m_plotter->ThickCircle( pos, radius * 2, thickness, GetMode() ); break; case S_ARC: { radius = KiROUND( GetLineLength( end, pos ) ); double startAngle = ArcTangente( end.y - pos.y, end.x - pos.x ); double endAngle = startAngle + aEdge->GetAngle(); m_plotter->ThickArc( pos, -endAngle, -startAngle, radius, thickness, GetMode() ); } break; case S_POLYGON: { const std::vector<wxPoint>& polyPoints = aEdge->GetPolyPoints(); if( polyPoints.size() <= 1 ) // Malformed polygon break; // We must compute true coordinates from m_PolyList // which are relative to module position, orientation 0 MODULE* module = aEdge->GetParentModule(); std::vector< wxPoint > cornerList; cornerList.reserve( polyPoints.size() ); for( unsigned ii = 0; ii < polyPoints.size(); ii++ ) { wxPoint corner = polyPoints[ii]; if( module ) { RotatePoint( &corner, module->GetOrientation() ); corner += module->GetPosition(); } cornerList.push_back( corner ); } m_plotter->PlotPoly( cornerList, FILLED_SHAPE, thickness ); } break; } }
void EDGE_MODULE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode, const wxPoint& offset ) { int ux0, uy0, dx, dy, radius, StAngle, EndAngle; LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer; MODULE* module = (MODULE*) m_Parent; if( !module ) return; BOARD* brd = GetBoard( ); if( brd->IsLayerVisible( m_Layer ) == false ) return; EDA_COLOR_T color = brd->GetLayerColor( m_Layer ); DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions(); if(( draw_mode & GR_ALLOW_HIGHCONTRAST ) && displ_opts && displ_opts->m_ContrastModeDisplay ) { if( !IsOnLayer( curr_layer ) ) ColorTurnToDarkDarkGray( &color ); } ux0 = m_Start.x - offset.x; uy0 = m_Start.y - offset.y; dx = m_End.x - offset.x; dy = m_End.y - offset.y; GRSetDrawMode( DC, draw_mode ); bool filled = displ_opts ? displ_opts->m_DisplayModEdgeFill : FILLED; if( IsCopperLayer( m_Layer ) ) filled = displ_opts ? displ_opts->m_DisplayPcbTrackFill : FILLED; switch( m_Shape ) { case S_SEGMENT: if( filled ) GRLine( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color ); else // SKETCH Mode GRCSegm( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color ); break; case S_CIRCLE: radius = KiROUND( Distance( ux0, uy0, dx, dy ) ); if( filled ) { GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, m_Width, color ); } else // SKETCH Mode { GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius + (m_Width / 2), color ); GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius - (m_Width / 2), color ); } break; case S_ARC: radius = KiROUND( Distance( ux0, uy0, dx, dy ) ); StAngle = ArcTangente( dy - uy0, dx - ux0 ); EndAngle = StAngle + m_Angle; if( !panel->GetPrintMirrored() ) { if( StAngle > EndAngle ) std::swap( StAngle, EndAngle ); } else // Mirrored mode: arc orientation is reversed { if( StAngle < EndAngle ) std::swap( StAngle, EndAngle ); } if( filled ) { GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius, m_Width, color ); } else // SKETCH Mode { GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius + (m_Width / 2), color ); GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius - (m_Width / 2), color ); } break; case S_POLYGON: { // We must compute absolute coordinates from m_PolyPoints // which are relative to module position, orientation 0 std::vector<wxPoint> points = m_PolyPoints; for( unsigned ii = 0; ii < points.size(); ii++ ) { wxPoint& pt = points[ii]; RotatePoint( &pt.x, &pt.y, module->GetOrientation() ); pt += module->GetPosition() - offset; } GRPoly( panel->GetClipBox(), DC, points.size(), &points[0], true, m_Width, color, color ); } break; default: break; } }
bool FOOTPRINT_EDIT_FRAME::Load_Module_From_BOARD( MODULE* aModule ) { MODULE* newModule; PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) Kiway().Player( FRAME_PCB, false ); if( frame == NULL ) // happens if no board editor opened return false; if( aModule == NULL ) { if( ! frame->GetBoard() || ! frame->GetBoard()->m_Modules ) return false; aModule = SelectFootprint( frame->GetBoard() ); } if( aModule == NULL ) return false; SetCurItem( NULL ); Clear_Pcb( false ); GetBoard()->m_Status_Pcb = 0; newModule = new MODULE( *aModule ); newModule->SetParent( GetBoard() ); newModule->SetLink( aModule->GetTimeStamp() ); aModule = newModule; newModule->ClearFlags(); newModule->RunOnChildren( boost::bind( &clearModuleItemFlags, _1 ) ); GetBoard()->Add( newModule ); // Clear references to any net info, because the footprint editor // does know any thing about nets handled by the current edited board. // Morever we do not want to save any reference to an unknown net when // saving the footprint in lib cache // so we force the ORPHANED dummy net info for all pads newModule->ClearAllNets(); SetCrossHairPosition( wxPoint( 0, 0 ) ); PlaceModule( newModule, NULL ); newModule->SetPosition( wxPoint( 0, 0 ) ); // cursor in GAL may not be initialized at the moment // Put it on FRONT layer, // because this is the default in ModEdit, and in libs if( newModule->GetLayer() != F_Cu ) newModule->Flip( newModule->GetPosition() ); // Put it in orientation 0, // because this is the default orientation in ModEdit, and in libs Rotate_Module( NULL, newModule, 0, false ); GetScreen()->ClrModify(); Zoom_Automatique( false ); if( IsGalCanvasActive() ) updateView(); return true; }
void EDA_3D_CANVAS::calcBBox() { BOARD* pcb = GetBoard(); m_fastAABBox.Reset(); for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) { CBBOX tmpFastAABBox; // Compute the transformation matrix for this module based on translation, rotation and orientation. float zpos = GetPrm3DVisu().GetModulesZcoord3DIU( module->IsFlipped() ); wxPoint pos = module->GetPosition(); glm::mat4 fullTransformMatrix; fullTransformMatrix = glm::translate( glm::mat4(), S3D_VERTEX( (float)(pos.x * GetPrm3DVisu().m_BiuTo3Dunits), (float)(-pos.y * GetPrm3DVisu().m_BiuTo3Dunits), zpos ) ); if( module->GetOrientation() ) fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( (float)(module->GetOrientation() / 10.0f) ), S3D_VERTEX( 0.0f, 0.0f, 1.0f ) ); if( module->IsFlipped() ) { fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( 180.0f ), S3D_VERTEX( 0.0f, 1.0f, 0.0f ) ); fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( 180.0f ), S3D_VERTEX( 0.0f, 0.0f, 1.0f ) ); } // Compute a union bounding box for all the shapes of the model S3D_MASTER* shape3D = module->Models(); for( ; shape3D; shape3D = shape3D->Next() ) { if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) ) tmpFastAABBox.Union( shape3D->getFastAABBox() ); } tmpFastAABBox.ApplyTransformationAA( fullTransformMatrix ); m_fastAABBox.Union( tmpFastAABBox ); } // Create a board bounding box based on board size wxSize brd_size = getBoardSize(); wxPoint brd_center_pos = getBoardCenter(); float xsize = brd_size.x; float ysize = brd_size.y; float scale = GetPrm3DVisu().m_BiuTo3Dunits; float xmin = (brd_center_pos.x - xsize / 2.0) * scale; float xmax = (brd_center_pos.x + xsize / 2.0) * scale; float ymin = (brd_center_pos.y - ysize / 2.0) * scale; float ymax = (brd_center_pos.y + ysize / 2.0) * scale; float zmin = GetPrm3DVisu().GetLayerZcoordBIU( B_Adhes ) * scale; float zmax = GetPrm3DVisu().GetLayerZcoordBIU( F_Adhes ) * scale; m_boardAABBox = CBBOX( S3D_VERTEX(xmin, ymin, zmin), S3D_VERTEX(xmax, ymax, zmax) ); // Add BB board with BB models and scale it a bit m_fastAABBox.Union( m_boardAABBox ); m_fastAABBox_Shadow = m_fastAABBox; m_fastAABBox_Shadow.Scale( SHADOW_BOUNDING_BOX_SCALE ); }
void PCB_PAINTER::draw( const DRAWSEGMENT* aSegment ) { const COLOR4D& color = m_pcbSettings.GetColor( aSegment, aSegment->GetLayer() ); m_gal->SetIsFill( false ); m_gal->SetIsStroke( true ); m_gal->SetStrokeColor( color ); m_gal->SetLineWidth( aSegment->GetWidth() ); switch( aSegment->GetShape() ) { case S_SEGMENT: m_gal->DrawLine( VECTOR2D( aSegment->GetStart() ), VECTOR2D( aSegment->GetEnd() ) ); break; case S_RECT: wxASSERT_MSG( false, wxT( "Not tested yet" ) ); m_gal->DrawRectangle( VECTOR2D( aSegment->GetStart() ), VECTOR2D( aSegment->GetEnd() ) ); break; case S_ARC: m_gal->DrawArc( VECTOR2D( aSegment->GetCenter() ), aSegment->GetRadius(), aSegment->GetArcAngleStart() * M_PI / 1800.0, ( aSegment->GetArcAngleStart() + aSegment->GetAngle() ) * M_PI / 1800.0 ); break; case S_CIRCLE: m_gal->DrawCircle( VECTOR2D( aSegment->GetCenter() ), aSegment->GetRadius() ); break; case S_POLYGON: { std::deque<VECTOR2D> pointsList; m_gal->SetIsFill( true ); m_gal->SetIsStroke( false ); m_gal->SetFillColor( color ); m_gal->Save(); MODULE* module = aSegment->GetParentModule(); if( module ) { m_gal->Translate( module->GetPosition() ); m_gal->Rotate( -module->GetOrientation() * M_PI / 1800.0 ); } else { // not tested m_gal->Translate( aSegment->GetPosition() ); m_gal->Rotate( -aSegment->GetAngle() * M_PI / 1800.0 ); } std::copy( aSegment->GetPolyPoints().begin(), aSegment->GetPolyPoints().end(), std::back_inserter( pointsList ) ); m_gal->SetLineWidth( aSegment->GetWidth() ); m_gal->DrawPolyline( pointsList ); m_gal->DrawPolygon( pointsList ); m_gal->Restore(); break; } case S_CURVE: m_gal->DrawCurve( VECTOR2D( aSegment->GetStart() ), VECTOR2D( aSegment->GetBezControl1() ), VECTOR2D( aSegment->GetBezControl2() ), VECTOR2D( aSegment->GetEnd() ) ); break; case S_LAST: break; } }
int MODULE_TOOLS::PasteItems( const TOOL_EVENT& aEvent ) { // Parse clipboard PCB_IO io( CTL_FOR_CLIPBOARD ); MODULE* pastedModule = NULL; try { BOARD_ITEM* item = io.Parse( wxString( m_toolMgr->GetClipboard().c_str(), wxConvUTF8 ) ); assert( item->Type() == PCB_MODULE_T ); pastedModule = dyn_cast<MODULE*>( item ); } catch( ... ) { m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) ); return 0; } // Placement tool part VECTOR2I cursorPos = m_controls->GetCursorPosition(); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( m_view ); pastedModule->SetParent( m_board ); pastedModule->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); pastedModule->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, std::ref( preview ), _1 ) ); preview.Add( pastedModule ); m_view->Add( &preview ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); m_controls->ShowCursor( true ); m_controls->SetSnapping( true ); m_controls->SetAutoPan( true ); Activate(); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { cursorPos = m_controls->GetCursorPosition(); if( evt->IsMotion() ) { pastedModule->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); m_view->Update( &preview ); } else if( evt->Category() == TC_COMMAND ) { if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { pastedModule->Rotate( pastedModule->GetPosition(), m_frame->GetRotationAngle() ); m_view->Update( &preview ); } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) { pastedModule->Flip( pastedModule->GetPosition() ); m_view->Update( &preview ); } else if( evt->IsCancel() || evt->IsActivate() ) { preview.Clear(); break; } } else if( evt->IsClick( BUT_LEFT ) ) { BOARD_COMMIT commit( m_frame ); m_board->m_Status_Pcb = 0; // I have no clue why, but it is done in the legacy view // MODULE::RunOnChildren is infeasible here: we need to create copies of items, do not // directly modify them for( D_PAD* pad = pastedModule->Pads(); pad; pad = pad->Next() ) { D_PAD* clone = static_cast<D_PAD*>( pad->Clone() ); commit.Add( clone ); } for( BOARD_ITEM* drawing = pastedModule->GraphicalItems(); drawing; drawing = drawing->Next() ) { BOARD_ITEM* clone = static_cast<BOARD_ITEM*>( drawing->Clone() ); if( TEXTE_MODULE* text = dyn_cast<TEXTE_MODULE*>( clone ) ) { // Do not add reference/value - convert them to the common type text->SetType( TEXTE_MODULE::TEXT_is_DIVERS ); // Whyyyyyyyyyyyyyyyyyyyyyy?! All other items conform to rotation performed // on its parent module, but texts are so independent.. text->Rotate( text->GetPosition(), pastedModule->GetOrientation() ); commit.Add( text ); } commit.Add( clone ); } commit.Push( _( "Paste clipboard contents" ) ); preview.Clear(); break; } } delete pastedModule; m_controls->ShowCursor( false ); m_controls->SetSnapping( false ); m_controls->SetAutoPan( false ); m_view->Remove( &preview ); return 0; }
int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent ) { MODULE* module = NULL; KIGFX::VIEW* view = getView(); KIGFX::VIEW_CONTROLS* controls = getViewControls(); BOARD* board = getModel<BOARD>(); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( view ); view->Add( &preview ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); controls->ShowCursor( true ); controls->SetSnapping( true ); Activate(); m_frame->SetToolID( ID_PCB_MODULE_BUTT, wxCURSOR_HAND, _( "Add footprint" ) ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { VECTOR2I cursorPos = controls->GetCursorPosition(); if( evt->IsCancel() || evt->IsActivate() ) { if( module ) { delete module; module = NULL; preview.Clear(); controls->ShowCursor( true ); } else break; if( evt->IsActivate() ) // now finish unconditionally break; } else if( module && evt->Category() == TC_COMMAND ) { if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { module->Rotate( module->GetPosition(), m_frame->GetRotationAngle() ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) { module->Flip( module->GetPosition() ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } else if( evt->IsClick( BUT_LEFT ) ) { if( !module ) { // Pick the module to be placed module = m_frame->LoadModuleFromLibrary( wxEmptyString, m_frame->Prj().PcbFootprintLibs(), true, NULL ); if( module == NULL ) continue; // Module has been added in LoadModuleFromLibrary(), // so we have to remove it before committing the change @todo LEGACY board->Remove( module ); module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); // Add all the drawable parts to preview preview.Add( module ); module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) ); } else { BOARD_COMMIT commit( m_frame ); commit.Add( module ); commit.Push( _( "Place a module" ) ); // Remove from preview preview.Remove( module ); module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Remove, &preview, _1 ) ); module = NULL; // to indicate that there is no module that we currently modify } bool placing = ( module != NULL ); controls->SetAutoPan( placing ); controls->CaptureCursor( placing ); controls->ShowCursor( !placing ); } else if( module && evt->IsMotion() ) { module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } controls->ShowCursor( false ); controls->SetSnapping( false ); controls->SetAutoPan( false ); controls->CaptureCursor( false ); view->Remove( &preview ); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
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; 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( aPcbFrame->GetUserUnits(), inductorPattern.m_length, true ); WX_TEXT_ENTRY_DIALOG dlg( aPcbFrame, _( "Length of Trace:" ), wxEmptyString, msg ); if( dlg.ShowModal() != wxID_OK ) return nullptr; // canceled by user msg = dlg.GetValue(); inductorPattern.m_length = ValueFromString( aPcbFrame->GetUserUnits(), 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; const INDUCTOR_S_SHAPE_RESULT res = BuildCornersList_S_Shape( buffer, inductorPattern.m_Start, inductorPattern.m_End, inductorPattern.m_length, inductorPattern.m_Width ); switch( res ) { case INDUCTOR_S_SHAPE_RESULT::TOO_LONG: aErrorMessage = _( "Requested length too large" ); return nullptr; case INDUCTOR_S_SHAPE_RESULT::TOO_SHORT: aErrorMessage = _( "Requested length too small" ); return nullptr; case INDUCTOR_S_SHAPE_RESULT::NO_REPR: aErrorMessage = _( "Requested length can't be represented" ); return nullptr; case INDUCTOR_S_SHAPE_RESULT::OK: break; } // Generate footprint. the value is also used as footprint name. msg = "L"; WX_TEXT_ENTRY_DIALOG cmpdlg( aPcbFrame, _( "Component Value:" ), wxEmptyString, 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 ); aPcbFrame->AddModuleToBoard( module ); module->SetFPID( LIB_ID( wxEmptyString, wxT( "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; }
bool DRC_COURTYARD_OVERLAP::RunDRC( BOARD& aBoard ) const { wxLogTrace( DRC_COURTYARD_TRACE, "Running DRC: Courtyard" ); // Detects missing (or malformed) footprint courtyard, // and for footprint with courtyard, courtyards overlap. wxString msg; bool success = true; const DRC_MARKER_FACTORY& marker_factory = GetMarkerFactory(); // Update courtyard polygons, and test for missing courtyard definition: for( MODULE* footprint = aBoard.m_Modules; footprint; footprint = footprint->Next() ) { wxPoint pos = footprint->GetPosition(); bool is_ok = footprint->BuildPolyCourtyard(); if( !is_ok && aBoard.GetDesignSettings().m_ProhibitOverlappingCourtyards ) { auto marker = std::unique_ptr<MARKER_PCB>( marker_factory.NewMarker( pos, footprint, DRCE_MALFORMED_COURTYARD_IN_FOOTPRINT ) ); HandleMarker( std::move( marker ) ); success = false; } if( !aBoard.GetDesignSettings().m_RequireCourtyards ) continue; if( footprint->GetPolyCourtyardFront().OutlineCount() == 0 && footprint->GetPolyCourtyardBack().OutlineCount() == 0 && is_ok ) { auto marker = std::unique_ptr<MARKER_PCB>( marker_factory.NewMarker( pos, footprint, DRCE_MISSING_COURTYARD_IN_FOOTPRINT ) ); HandleMarker( std::move( marker ) ); success = false; } } if( !aBoard.GetDesignSettings().m_ProhibitOverlappingCourtyards ) return success; wxLogTrace( DRC_COURTYARD_TRACE, "Checking for courtyard overlap" ); // Now test for overlapping on top layer: SHAPE_POLY_SET courtyard; // temporary storage of the courtyard of current footprint for( MODULE* footprint = aBoard.m_Modules; footprint; footprint = footprint->Next() ) { if( footprint->GetPolyCourtyardFront().OutlineCount() == 0 ) continue; // No courtyard defined for( MODULE* candidate = footprint->Next(); candidate; candidate = candidate->Next() ) { if( candidate->GetPolyCourtyardFront().OutlineCount() == 0 ) continue; // No courtyard defined courtyard.RemoveAllContours(); courtyard.Append( footprint->GetPolyCourtyardFront() ); // Build the common area between footprint and the candidate: courtyard.BooleanIntersection( candidate->GetPolyCourtyardFront(), SHAPE_POLY_SET::PM_FAST ); // If no overlap, courtyard is empty (no common area). // Therefore if a common polygon exists, this is a DRC error if( courtyard.OutlineCount() ) { //Overlap between footprint and candidate VECTOR2I& pos = courtyard.Vertex( 0, 0, -1 ); auto marker = std::unique_ptr<MARKER_PCB>( marker_factory.NewMarker( wxPoint( pos.x, pos.y ), footprint, candidate, DRCE_OVERLAPPING_FOOTPRINTS ) ); HandleMarker( std::move( marker ) ); success = false; } } } // Test for overlapping on bottom layer: for( MODULE* footprint = aBoard.m_Modules; footprint; footprint = footprint->Next() ) { if( footprint->GetPolyCourtyardBack().OutlineCount() == 0 ) continue; // No courtyard defined for( MODULE* candidate = footprint->Next(); candidate; candidate = candidate->Next() ) { if( candidate->GetPolyCourtyardBack().OutlineCount() == 0 ) continue; // No courtyard defined courtyard.RemoveAllContours(); courtyard.Append( footprint->GetPolyCourtyardBack() ); // Build the common area between footprint and the candidate: courtyard.BooleanIntersection( candidate->GetPolyCourtyardBack(), SHAPE_POLY_SET::PM_FAST ); // If no overlap, courtyard is empty (no common area). // Therefore if a common polygon exists, this is a DRC error if( courtyard.OutlineCount() ) { //Overlap between footprint and candidate VECTOR2I& pos = courtyard.Vertex( 0, 0, -1 ); auto marker = std::unique_ptr<MARKER_PCB>( marker_factory.NewMarker( wxPoint( pos.x, pos.y ), footprint, candidate, DRCE_OVERLAPPING_FOOTPRINTS ) ); HandleMarker( std::move( marker ) ); success = false; } } } return success; }
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; }
MODULE* CreateMicrowaveInductor( 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; wxASSERT( s_inductor_pattern.m_Flag ); s_inductor_pattern.m_Flag = false; wxPoint pt = s_inductor_pattern.m_End - s_inductor_pattern.m_Start; int min_len = KiROUND( EuclideanNorm( pt ) ); s_inductor_pattern.m_length = min_len; // Enter the desired length. msg = StringFromValue( g_UserUnit, s_inductor_pattern.m_length ); wxTextEntryDialog dlg( NULL, wxEmptyString, _( "Length of Trace:" ), msg ); if( dlg.ShowModal() != wxID_OK ) return NULL; // canceled by user msg = dlg.GetValue(); s_inductor_pattern.m_length = ValueFromString( g_UserUnit, msg ); // Control values (ii = minimum length) if( s_inductor_pattern.m_length < min_len ) { aErrorMessage = _( "Requested length < minimum length" ); return NULL; } // Calculate the elements. std::vector <wxPoint> buffer; ll = BuildCornersList_S_Shape( buffer, s_inductor_pattern.m_Start, s_inductor_pattern.m_End, s_inductor_pattern.m_length, s_inductor_pattern.m_Width ); if( !ll ) { aErrorMessage = _( "Requested length too large" ); return NULL; } // Generate footprint. the value is also used as footprint name. msg.Empty(); wxTextEntryDialog cmpdlg( NULL, 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 = aPcbFrame->CreateNewModule( msg ); // here the module is already in the BOARD, CreateNewModule() does that. module->SetFPID( LIB_ID( 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. 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(); return module; }
const EDA_RECT DRAWSEGMENT::GetBoundingBox() const { EDA_RECT bbox; bbox.SetOrigin( m_Start ); switch( m_Shape ) { case S_SEGMENT: bbox.SetEnd( m_End ); break; case S_CIRCLE: bbox.Inflate( GetRadius() ); break; case S_ARC: { bbox.Merge( m_End ); wxPoint end = m_End; RotatePoint( &end, m_Start, -m_Angle ); bbox.Merge( end ); // Determine the starting quarter // 0 right-bottom // 1 left-bottom // 2 left-top // 3 right-top unsigned int quarter = 0; // assume right-bottom if( m_End.y < m_Start.y ) // change to left-top quarter |= 3; if( m_End.x < m_Start.x ) // for left side, the LSB is 2nd bit negated quarter ^= 1; int radius = GetRadius(); int angle = (int) GetArcAngleStart() % 900 + m_Angle; bool directionCW = ( m_Angle > 0 ); // Is the direction of arc clockwise? if( !directionCW ) { angle = 900 - angle; quarter = ( quarter + 3 ) % 4; // -1 modulo arithmetic } while( angle > 900 ) { switch( quarter ) { case 0: bbox.Merge( wxPoint( m_Start.x, m_Start.y + radius ) ); // down break; case 1: bbox.Merge( wxPoint( m_Start.x - radius, m_Start.y ) ); // left break; case 2: bbox.Merge( wxPoint( m_Start.x, m_Start.y - radius ) ); // up break; case 3: bbox.Merge( wxPoint( m_Start.x + radius, m_Start.y ) ); // right break; } if( directionCW ) ++quarter; else quarter += 3; // -1 modulo arithmetic quarter %= 4; angle -= 900; } } break; case S_POLYGON: { wxPoint p_end; MODULE* module = GetParentModule(); for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) { wxPoint pt = m_PolyPoints[ii]; if( module ) // Transform, if we belong to a module { RotatePoint( &pt, module->GetOrientation() ); pt += module->GetPosition(); } if( ii == 0 ) p_end = pt; bbox.SetX( std::min( bbox.GetX(), pt.x ) ); bbox.SetY( std::min( bbox.GetY(), pt.y ) ); p_end.x = std::max( p_end.x, pt.x ); p_end.y = std::max( p_end.y, pt.y ); } bbox.SetEnd( p_end ); } break; default: ; } bbox.Inflate( ((m_Width+1) / 2) + 1 ); bbox.Normalize(); return bbox; }
/** * Function ConvertOutlineToPolygon * build a polygon (with holes) from a DRAWSEGMENT list, which is expected to be * a outline, therefore a closed main outline with perhaps closed inner outlines. * These closed inner outlines are considered as holes in the main outline * @param aSegList the initial list of drawsegments (only lines, circles and arcs). * @param aPolygons will contain the complex polygon. * @param aTolerance is the max distance between points that is still accepted as connected (internal units) * @param aErrorText is a wxString to return error message. * @param aErrorLocation is the optional position of the error in the outline */ bool ConvertOutlineToPolygon( std::vector<DRAWSEGMENT*>& aSegList, SHAPE_POLY_SET& aPolygons, wxString* aErrorText, unsigned int aTolerance, wxPoint* aErrorLocation ) { if( aSegList.size() == 0 ) return true; wxString msg; // Make a working copy of aSegList, because the list is modified during calculations std::vector< DRAWSEGMENT* > segList = aSegList; DRAWSEGMENT* graphic; wxPoint prevPt; // Find edge point with minimum x, this should be in the outer polygon // which will define the perimeter Edge.Cuts polygon. wxPoint xmin = wxPoint( INT_MAX, 0 ); int xmini = 0; for( size_t i = 0; i < segList.size(); i++ ) { graphic = (DRAWSEGMENT*) segList[i]; switch( graphic->GetShape() ) { case S_SEGMENT: { if( graphic->GetStart().x < xmin.x ) { xmin = graphic->GetStart(); xmini = i; } if( graphic->GetEnd().x < xmin.x ) { xmin = graphic->GetEnd(); xmini = i; } } break; case S_ARC: // Freerouter does not yet understand arcs, so approximate // an arc with a series of short lines and put those // line segments into the !same! PATH. { wxPoint pstart = graphic->GetArcStart(); wxPoint center = graphic->GetCenter(); double angle = -graphic->GetAngle(); double radius = graphic->GetRadius(); int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 ); wxPoint pt; for( int step = 1; step<=steps; ++step ) { double rotation = ( angle * step ) / steps; pt = pstart; RotatePoint( &pt, center, rotation ); if( pt.x < xmin.x ) { xmin = pt; xmini = i; } } } break; case S_CIRCLE: { wxPoint pt = graphic->GetCenter(); // pt has minimum x point pt.x -= graphic->GetRadius(); // when the radius <= 0, this is a mal-formed circle. Skip it if( graphic->GetRadius() > 0 && pt.x < xmin.x ) { xmin = pt; xmini = i; } } break; case S_CURVE: { graphic->RebuildBezierToSegmentsPointsList( graphic->GetWidth() ); for( unsigned int jj = 0; jj < graphic->GetBezierPoints().size(); jj++ ) { wxPoint pt = graphic->GetBezierPoints()[jj]; if( pt.x < xmin.x ) { xmin = pt; xmini = i; } } } break; case S_POLYGON: { const auto poly = graphic->GetPolyShape(); MODULE* module = aSegList[0]->GetParentModule(); double orientation = module ? module->GetOrientation() : 0.0; VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 ); for( auto iter = poly.CIterate(); iter; iter++ ) { auto pt = *iter; RotatePoint( pt, orientation ); pt += offset; if( pt.x < xmin.x ) { xmin.x = pt.x; xmin.y = pt.y; xmini = i; } } } break; default: break; } } // Grab the left most point, assume its on the board's perimeter, and see if we // can put enough graphics together by matching endpoints to formulate a cohesive // polygon. graphic = (DRAWSEGMENT*) segList[xmini]; // The first DRAWSEGMENT is in 'graphic', ok to remove it from 'items' segList.erase( segList.begin() + xmini ); // Output the Edge.Cuts perimeter as circle or polygon. if( graphic->GetShape() == S_CIRCLE ) { int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_LOW_DEF, 360.0 ); TransformCircleToPolygon( aPolygons, graphic->GetCenter(), graphic->GetRadius(), steps ); } else if( graphic->GetShape() == S_POLYGON ) { MODULE* module = graphic->GetParentModule(); // NULL for items not in footprints double orientation = module ? module->GetOrientation() : 0.0; VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 ); aPolygons.NewOutline(); for( auto it = graphic->GetPolyShape().CIterate( 0 ); it; it++ ) { auto pt = *it; RotatePoint( pt, orientation ); pt += offset; aPolygons.Append( pt ); } } else { // Polygon start point. Arbitrarily chosen end of the // segment and build the poly from here. wxPoint startPt = wxPoint( graphic->GetEnd() ); prevPt = graphic->GetEnd(); aPolygons.NewOutline(); aPolygons.Append( prevPt ); // Do not append the other end point yet of this 'graphic', this first // 'graphic' might be an arc or a curve. for(;;) { switch( graphic->GetShape() ) { case S_SEGMENT: { wxPoint nextPt; // Use the line segment end point furthest away from // prevPt as we assume the other end to be ON prevPt or // very close to it. if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) ) nextPt = graphic->GetEnd(); else nextPt = graphic->GetStart(); aPolygons.Append( nextPt ); prevPt = nextPt; } break; case S_ARC: // We do not support arcs in polygons, so approximate // an arc with a series of short lines and put those // line segments into the !same! PATH. { wxPoint pstart = graphic->GetArcStart(); wxPoint pend = graphic->GetArcEnd(); wxPoint pcenter = graphic->GetCenter(); double angle = -graphic->GetAngle(); double radius = graphic->GetRadius(); int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 ); if( !close_enough( prevPt, pstart, aTolerance ) ) { wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) ); angle = -angle; std::swap( pstart, pend ); } wxPoint nextPt; for( int step = 1; step<=steps; ++step ) { double rotation = ( angle * step ) / steps; nextPt = pstart; RotatePoint( &nextPt, pcenter, rotation ); aPolygons.Append( nextPt ); } prevPt = nextPt; } break; case S_CURVE: // We do not support Bezier curves in polygons, so approximate // with a series of short lines and put those // line segments into the !same! PATH. { wxPoint nextPt; bool reverse = false; // Use the end point furthest away from // prevPt as we assume the other end to be ON prevPt or // very close to it. if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) ) nextPt = graphic->GetEnd(); else { nextPt = graphic->GetStart(); reverse = true; } if( reverse ) { for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- ) aPolygons.Append( graphic->GetBezierPoints()[jj] ); } else { for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ ) aPolygons.Append( graphic->GetBezierPoints()[jj] ); } prevPt = nextPt; } break; default: if( aErrorText ) { msg.Printf( "Unsupported DRAWSEGMENT type %s.", BOARD_ITEM::ShowShape( graphic->GetShape() ) ); *aErrorText << msg << "\n"; } if( aErrorLocation ) *aErrorLocation = graphic->GetPosition(); return false; } // Get next closest segment. graphic = findPoint( prevPt, segList, aTolerance ); // If there are no more close segments, check if the board // outline polygon can be closed. if( !graphic ) { if( close_enough( startPt, prevPt, aTolerance ) ) { // Close the polygon back to start point // aPolygons.Append( startPt ); // not needed } else { if( aErrorText ) { msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ), StringFromValue( MILLIMETRES, prevPt.x, true ), StringFromValue( MILLIMETRES, prevPt.y, true ) ); *aErrorText << msg << "\n"; } if( aErrorLocation ) *aErrorLocation = prevPt; return false; } break; } } } while( segList.size() ) { // emit a signal layers keepout for every interior polygon left... int hole = aPolygons.NewHole(); graphic = (DRAWSEGMENT*) segList[0]; segList.erase( segList.begin() ); // Both circles and polygons on the edge cuts layer are closed items that // do not connect to other elements, so we process them independently if( graphic->GetShape() == S_POLYGON ) { MODULE* module = graphic->GetParentModule(); // NULL for items not in footprints double orientation = module ? module->GetOrientation() : 0.0; VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 ); for( auto it = graphic->GetPolyShape().CIterate(); it; it++ ) { auto val = *it; RotatePoint( val, orientation ); val += offset; aPolygons.Append( val, -1, hole ); } } else if( graphic->GetShape() == S_CIRCLE ) { // make a circle by segments; wxPoint center = graphic->GetCenter(); double angle = 3600.0; wxPoint start = center; int radius = graphic->GetRadius(); int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, 360.0 ); wxPoint nextPt; start.x += radius; for( int step = 0; step < steps; ++step ) { double rotation = ( angle * step ) / steps; nextPt = start; RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation ); aPolygons.Append( nextPt, -1, hole ); } } else { // Polygon start point. Arbitrarily chosen end of the // segment and build the poly from here. wxPoint startPt( graphic->GetEnd() ); prevPt = graphic->GetEnd(); aPolygons.Append( prevPt, -1, hole ); // do not append the other end point yet, this first 'graphic' might be an arc for(;;) { switch( graphic->GetShape() ) { case S_SEGMENT: { wxPoint nextPt; // Use the line segment end point furthest away from // prevPt as we assume the other end to be ON prevPt or // very close to it. if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) ) { nextPt = graphic->GetEnd(); } else { nextPt = graphic->GetStart(); } prevPt = nextPt; aPolygons.Append( prevPt, -1, hole ); } break; case S_ARC: // Freerouter does not yet understand arcs, so approximate // an arc with a series of short lines and put those // line segments into the !same! PATH. { wxPoint pstart = graphic->GetArcStart(); wxPoint pend = graphic->GetArcEnd(); wxPoint pcenter = graphic->GetCenter(); double angle = -graphic->GetAngle(); int radius = graphic->GetRadius(); int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 ); if( !close_enough( prevPt, pstart, aTolerance ) ) { wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) ); angle = -angle; std::swap( pstart, pend ); } wxPoint nextPt; for( int step = 1; step <= steps; ++step ) { double rotation = ( angle * step ) / steps; nextPt = pstart; RotatePoint( &nextPt, pcenter, rotation ); aPolygons.Append( nextPt, -1, hole ); } prevPt = nextPt; } break; case S_CURVE: // We do not support Bezier curves in polygons, so approximate // with a series of short lines and put those // line segments into the !same! PATH. { wxPoint nextPt; bool reverse = false; // Use the end point furthest away from // prevPt as we assume the other end to be ON prevPt or // very close to it. if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) ) nextPt = graphic->GetEnd(); else { nextPt = graphic->GetStart(); reverse = true; } if( reverse ) { for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- ) aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole ); } else { for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ ) aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole ); } prevPt = nextPt; } break; default: if( aErrorText ) { msg.Printf( "Unsupported DRAWSEGMENT type %s.", BOARD_ITEM::ShowShape( graphic->GetShape() ) ); *aErrorText << msg << "\n"; } if( aErrorLocation ) *aErrorLocation = graphic->GetPosition(); return false; } // Get next closest segment. graphic = findPoint( prevPt, segList, aTolerance ); // If there are no more close segments, check if polygon // can be closed. if( !graphic ) { if( close_enough( startPt, prevPt, aTolerance ) ) { // Close the polygon back to start point // aPolygons.Append( startPt, -1, hole ); // not needed } else { if( aErrorText ) { msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ), StringFromValue( MILLIMETRES, prevPt.x, true ), StringFromValue( MILLIMETRES, prevPt.y, true ) ); *aErrorText << msg << "\n"; } if( aErrorLocation ) *aErrorLocation = prevPt; return false; } break; } } } } return true; }
void WinEDA_PcbFindFrame::FindItem( wxCommandEvent& event ) { PCB_SCREEN* screen = (PCB_SCREEN*) ( m_Parent->GetScreen() ); wxPoint locate_pos; wxString msg; bool FindMarker = false; BOARD_ITEM* foundItem = 0; switch( event.GetId() ) { case ID_FIND_ITEM: s_ItemCount = 0; break; case ID_FIND_MARKER: s_MarkerCount = 0; // fall thru case ID_FIND_NEXT_MARKER: FindMarker = true; break; } s_OldStringFound = m_NewText->GetValue(); m_Parent->GetCanvas()->GetViewStart( &screen->m_StartVisu.x, &screen->m_StartVisu.y ); if( FindMarker ) { MARKER_PCB* marker = m_Parent->GetBoard()->GetMARKER( s_MarkerCount++ ); if( marker ) { foundItem = marker; locate_pos = marker->GetPosition(); } } else { int StartCount = 0; for( MODULE* module = m_Parent->GetBoard()->m_Modules; module; module = module->Next() ) { if( WildCompareString( s_OldStringFound, module->GetReference().GetData(), false ) ) { StartCount++; if( StartCount > s_ItemCount ) { foundItem = module; locate_pos = module->GetPosition(); s_ItemCount++; break; } } if( WildCompareString( s_OldStringFound, module->m_Value->m_Text.GetData(), false ) ) { StartCount++; if( StartCount > s_ItemCount ) { foundItem = module; locate_pos = module->m_Pos; s_ItemCount++; break; } } } } if( foundItem ) { m_Parent->SetCurItem( foundItem ); if( FindMarker ) msg = _( "Marker found" ); else msg.Printf( _( "<%s> Found" ), GetChars( s_OldStringFound ) ); m_Parent->SetStatusText( msg ); m_Parent->CursorGoto( locate_pos ); EndModal( 1 ); } else { m_Parent->SetStatusText( wxEmptyString ); if( FindMarker ) msg = _( "Marker not found" ); else msg.Printf( _( "<%s> Not Found" ), GetChars( s_OldStringFound ) ); DisplayError( this, msg, 10 ); EndModal( 0 ); } }
void FOOTPRINT_EDIT_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos ) { BOARD_ITEM* item = GetCurItem(); m_canvas->CrossHairOff( DC ); if( GetToolId() == ID_NO_TOOL_SELECTED ) { if( item && item->GetFlags() ) // Move item command in progress { switch( item->Type() ) { case PCB_MODULE_TEXT_T: PlaceTexteModule( static_cast<TEXTE_MODULE*>( item ), DC ); break; case PCB_MODULE_EDGE_T: SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); Place_EdgeMod( static_cast<EDGE_MODULE*>( item ) ); break; case PCB_PAD_T: PlacePad( static_cast<D_PAD*>( item ), DC ); break; default: { wxString msg; msg.Printf( wxT( "WinEDA_ModEditFrame::OnLeftClick err:Struct %d, m_Flag %X" ), item->Type(), item->GetFlags() ); DisplayError( this, msg ); item->ClearFlags(); break; } } } else { if( !wxGetKeyState( WXK_SHIFT ) && !wxGetKeyState( WXK_ALT ) && !wxGetKeyState( WXK_CONTROL ) ) item = ModeditLocateAndDisplay(); SetCurItem( item ); } } item = GetCurItem(); bool no_item_edited = item == NULL || item->GetFlags() == 0; switch( GetToolId() ) { case ID_NO_TOOL_SELECTED: break; case ID_MODEDIT_CIRCLE_TOOL: case ID_MODEDIT_ARC_TOOL: case ID_MODEDIT_LINE_TOOL: if( no_item_edited ) { STROKE_T shape = S_SEGMENT; if( GetToolId() == ID_MODEDIT_CIRCLE_TOOL ) shape = S_CIRCLE; if( GetToolId() == ID_MODEDIT_ARC_TOOL ) shape = S_ARC; SetCurItem( Begin_Edge_Module( (EDGE_MODULE*) NULL, DC, shape ) ); } else if( item->IsNew() ) { if( ( (EDGE_MODULE*) item )->GetShape() == S_CIRCLE ) { End_Edge_Module( (EDGE_MODULE*) item ); SetCurItem( NULL ); m_canvas->Refresh(); } else if( ( (EDGE_MODULE*) item )->GetShape() == S_ARC ) { End_Edge_Module( (EDGE_MODULE*) item ); SetCurItem( NULL ); m_canvas->Refresh(); } else if( ( (EDGE_MODULE*) item )->GetShape() == S_SEGMENT ) { SetCurItem( Begin_Edge_Module( (EDGE_MODULE*) item, DC, S_SEGMENT ) ); } else { wxMessageBox( wxT( "ProcessCommand error: unknown shape" ) ); } } break; case ID_MODEDIT_DELETE_TOOL: if( ! no_item_edited ) // Item in edit, cannot delete it break; item = ModeditLocateAndDisplay(); if( item && item->Type() != PCB_MODULE_T ) // Cannot delete the module itself { SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); RemoveStruct( item ); SetCurItem( NULL ); } break; case ID_MODEDIT_ANCHOR_TOOL: { MODULE* module = GetBoard()->m_Modules; if( module == NULL // No module loaded || (module->GetFlags() != 0) ) break; SaveCopyInUndoList( module, UR_MODEDIT ); // set the new relative internal local coordinates of footprint items wxPoint moveVector = module->GetPosition() - GetCrossHairPosition(); module->MoveAnchorPosition( moveVector ); // Usually, we do not need to change twice the anchor position, // so deselect the active tool SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); SetCurItem( NULL ); m_canvas->Refresh(); } break; case ID_MODEDIT_PLACE_GRID_COORD: m_canvas->DrawGridAxis( DC, GR_XOR, GetBoard()->GetGridOrigin() ); SetGridOrigin( GetCrossHairPosition() ); m_canvas->DrawGridAxis( DC, GR_COPY, GetBoard()->GetGridOrigin() ); GetScreen()->SetModify(); break; case ID_MODEDIT_TEXT_TOOL: if( GetBoard()->m_Modules == NULL ) break; SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); CreateTextModule( GetBoard()->m_Modules, DC ); break; case ID_MODEDIT_PAD_TOOL: if( GetBoard()->m_Modules ) { SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); AddPad( GetBoard()->m_Modules, true ); } break; default: DisplayError( this, wxT( "FOOTPRINT_EDIT_FRAME::ProcessCommand error" ) ); SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); } m_canvas->CrossHairOn( DC ); }
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; }
int MODULE_TOOLS::CopyItems( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection(); Activate(); m_controls->SetSnapping( true ); m_controls->ShowCursor( true ); m_controls->SetAutoPan( true ); m_frame->DisplayToolMsg( _( "Select reference point" ) ); bool cancelled = false; VECTOR2I cursorPos = m_controls->GetCursorPosition(); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsMotion() ) { cursorPos = m_controls->GetCursorPosition(); } else if( evt->IsClick( BUT_LEFT ) ) { break; } else if( evt->IsCancel() || evt->IsActivate() ) { cancelled = true; break; } } if( !cancelled ) { PCB_IO io( CTL_FOR_CLIPBOARD ); // Create a temporary module that contains selected items to ease serialization MODULE module( m_board ); for( auto item : selection ) { auto clone = static_cast<BOARD_ITEM*>( item->Clone() ); // Do not add reference/value - convert them to the common type if( TEXTE_MODULE* text = dyn_cast<TEXTE_MODULE*>( clone ) ) text->SetType( TEXTE_MODULE::TEXT_is_DIVERS ); module.Add( clone ); } // Set the new relative internal local coordinates of copied items MODULE* editedModule = m_board->m_Modules; wxPoint moveVector = module.GetPosition() + editedModule->GetPosition() - wxPoint( cursorPos.x, cursorPos.y ); module.MoveAnchorPosition( moveVector ); io.Format( &module, 0 ); std::string data = io.GetStringOutput( true ); m_toolMgr->SaveClipboard( data ); } m_frame->DisplayToolMsg( wxString::Format( _( "Copied %d item(s)" ), selection.Size() ) ); m_controls->SetSnapping( false ); m_controls->ShowCursor( false ); m_controls->SetAutoPan( false ); return 0; }
// Handles the selection of command events. void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) { int id = event.GetId(); LAYER_NUM itmp; INSTALL_UNBUFFERED_DC( dc, m_canvas ); MODULE* module; m_canvas->CrossHairOff( &dc ); switch( id ) // Some (not all ) edit commands must be finished or aborted { case wxID_CUT: case wxID_COPY: case ID_PCB_USER_GRID_SETUP: case ID_TOOLBARH_PCB_SELECT_LAYER: case ID_AUX_TOOLBAR_PCB_SELECT_LAYER_PAIR: case ID_POPUP_PCB_ROTATE_TEXTEPCB: case ID_POPUP_PCB_FLIP_TEXTEPCB: case ID_POPUP_PCB_COPY_TEXTEPCB: case ID_POPUP_PCB_EDIT_TEXTEPCB: case ID_POPUP_PCB_EDIT_MIRE: case ID_POPUP_PCB_ROTATE_TEXTMODULE: case ID_POPUP_PCB_ROTATE_MODULE_CLOCKWISE: case ID_POPUP_PCB_ROTATE_MODULE_COUNTERCLOCKWISE: case ID_POPUP_PCB_CHANGE_SIDE_MODULE: case ID_POPUP_PCB_EDIT_MODULE_PRMS: case ID_POPUP_PCB_EDIT_MODULE_WITH_MODEDIT: case ID_POPUP_PCB_EDIT_TEXTMODULE: case ID_POPUP_PCB_STOP_CURRENT_DRAWING: case ID_POPUP_PCB_BEGIN_TRACK: case ID_POPUP_PCB_END_TRACK: case ID_POPUP_PCB_PLACE_THROUGH_VIA: case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA: case ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA: case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA: case ID_POPUP_PCB_PLACE_MICROVIA: case ID_POPUP_PCB_SWITCH_TRACK_POSTURE: case ID_POPUP_PCB_IMPORT_PAD_SETTINGS: case ID_POPUP_PCB_EXPORT_PAD_SETTINGS: case ID_POPUP_PCB_GLOBAL_IMPORT_PAD_SETTINGS: case ID_POPUP_PCB_STOP_CURRENT_EDGE_ZONE: case ID_POPUP_PCB_DELETE_ZONE_LAST_CREATED_CORNER: case ID_POPUP_PCB_FILL_ALL_ZONES: case ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_ALL_ZONES: case ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_CURRENT_ZONE: case ID_POPUP_PCB_PLACE_ZONE_CORNER: case ID_POPUP_PCB_PLACE_ZONE_OUTLINES: case ID_POPUP_PCB_EDIT_ZONE_PARAMS: case ID_POPUP_PCB_DELETE_ZONE: case ID_POPUP_PCB_MOVE_ZONE_CORNER: case ID_POPUP_PCB_DRAG_ZONE_OUTLINE_SEGMENT: case ID_POPUP_PCB_MOVE_ZONE_OUTLINES: case ID_POPUP_PCB_ADD_ZONE_CORNER: case ID_POPUP_PCB_DELETE_TRACKSEG: case ID_POPUP_PCB_DELETE_TRACK: case ID_POPUP_PCB_DELETE_TRACKNET: case ID_POPUP_PCB_FILL_ZONE: case ID_POPUP_PCB_SELECT_LAYER: case ID_POPUP_PCB_SELECT_CU_LAYER: case ID_POPUP_PCB_SELECT_LAYER_PAIR: case ID_POPUP_PCB_SELECT_NO_CU_LAYER: case ID_POPUP_PCB_MOVE_TRACK_NODE: case ID_POPUP_PCB_MOVE_TEXTEPCB_REQUEST: case ID_POPUP_PCB_DRAG_TRACK_SEGMENT_KEEP_SLOPE: case ID_POPUP_PCB_DRAG_TRACK_SEGMENT: case ID_POPUP_PCB_MOVE_TRACK_SEGMENT: case ID_POPUP_PCB_PLACE_MOVED_TRACK_NODE: case ID_POPUP_PCB_BREAK_TRACK: case ID_POPUP_PCB_EDIT_NET: case ID_POPUP_PCB_EDIT_TRACK: case ID_POPUP_PCB_EDIT_TRACKSEG: case ID_POPUP_PCB_LOCK_ON_TRACKSEG: case ID_POPUP_PCB_LOCK_OFF_TRACKSEG: case ID_POPUP_PCB_LOCK_ON_TRACK: case ID_POPUP_PCB_LOCK_OFF_TRACK: case ID_POPUP_PCB_LOCK_ON_NET: case ID_POPUP_PCB_LOCK_OFF_NET: case ID_POPUP_DELETE_BLOCK: case ID_POPUP_PLACE_BLOCK: case ID_POPUP_ZOOM_BLOCK: case ID_POPUP_FLIP_BLOCK: case ID_POPUP_ROTATE_BLOCK: case ID_POPUP_COPY_BLOCK: case ID_POPUP_PCB_EDIT_DRAWING: case ID_POPUP_PCB_GETINFO_MARKER: case ID_POPUP_PCB_MOVE_TEXT_DIMENSION_REQUEST: case ID_POPUP_PCB_DRAG_MODULE_REQUEST: case ID_POPUP_PCB_MOVE_MODULE_REQUEST: case ID_POPUP_PCB_MOVE_TEXTMODULE_REQUEST: case ID_POPUP_PCB_MOVE_MIRE_REQUEST: break; case ID_POPUP_CANCEL_CURRENT_COMMAND: if( m_canvas->IsMouseCaptured() ) { m_canvas->EndMouseCapture(); } // Should not be executed, just in case if( GetScreen()->m_BlockLocate.GetCommand() != BLOCK_IDLE ) { GetScreen()->m_BlockLocate.SetCommand( BLOCK_IDLE ); GetScreen()->m_BlockLocate.SetState( STATE_NO_BLOCK ); GetScreen()->m_BlockLocate.ClearItemsList(); } if( GetToolId() == ID_NO_TOOL_SELECTED ) SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); else SetCursor( (wxStockCursor) m_canvas->GetDefaultCursor() ); break; default: // Finish (abort) the command if( m_canvas->IsMouseCaptured() ) m_canvas->CallEndMouseCapture( &dc ); if( GetToolId() != id ) { if( m_lastDrawToolId != GetToolId() ) m_lastDrawToolId = GetToolId(); SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); } break; } switch( id ) // Execute command { case 0: break; case ID_OPEN_MODULE_EDITOR: { FOOTPRINT_EDIT_FRAME* editor = (FOOTPRINT_EDIT_FRAME*) Kiway().Player( FRAME_PCB_MODULE_EDITOR, false ); if( !editor ) { editor = (FOOTPRINT_EDIT_FRAME*) Kiway().Player( FRAME_PCB_MODULE_EDITOR, true ); editor->Show( true ); editor->Zoom_Automatique( false ); } else { /* not needed on linux, other platforms need this? if( editor->IsIconized() ) editor->Iconize( false ); */ editor->Raise(); // Raising the window does not set the focus on Linux. This should work on // any platform. if( wxWindow::FindFocus() != editor ) editor->SetFocus(); } } break; case ID_OPEN_MODULE_VIEWER: { FOOTPRINT_VIEWER_FRAME* viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER, false ); if( !viewer ) { viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER, true ); viewer->Show( true ); viewer->Zoom_Automatique( false ); } else { /* not needed on linux, other platforms need this? if( viewer->IsIconized() ) viewer->Iconize( false ); */ viewer->Raise(); // Raising the window does not set the focus on Linux. This should work on // any platform. if( wxWindow::FindFocus() != viewer ) viewer->SetFocus(); } } break; case ID_PCB_GLOBAL_DELETE: InstallPcbGlobalDeleteFrame( wxDefaultPosition ); break; case ID_POPUP_PLACE_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_MOVE ); m_canvas->SetAutoPanRequest( false ); HandleBlockPlace( &dc ); break; case ID_POPUP_COPY_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_COPY ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); m_canvas->SetAutoPanRequest( false ); HandleBlockPlace( &dc ); break; case ID_POPUP_ZOOM_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_ZOOM ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); HandleBlockEnd( &dc ); break; case ID_POPUP_DELETE_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_DELETE ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); HandleBlockEnd( &dc ); break; case ID_POPUP_ROTATE_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_ROTATE ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); HandleBlockEnd( &dc ); break; case ID_POPUP_FLIP_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_FLIP ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); HandleBlockEnd( &dc ); break; case ID_DRC_CONTROL: m_drc->ShowDialog(); break; case ID_GET_NETLIST: InstallNetlistFrame( &dc ); break; case ID_FIND_ITEMS: InstallFindFrame(); break; case ID_POPUP_CLOSE_CURRENT_TOOL: SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); break; case ID_POPUP_CANCEL_CURRENT_COMMAND: break; case ID_POPUP_PCB_END_LINE: m_canvas->MoveCursorToCrossHair(); // EndSegment(&dc); break; case ID_POPUP_PCB_EDIT_TRACK: if( GetCurItem() == NULL ) break; Edit_Track_Width( &dc, (TRACK*) GetCurItem() ); m_canvas->MoveCursorToCrossHair(); OnModify(); break; case ID_POPUP_PCB_EDIT_TRACKSEG: if( GetCurItem() == NULL ) break; Edit_TrackSegm_Width( &dc, (TRACK*) GetCurItem() ); m_canvas->MoveCursorToCrossHair(); OnModify(); break; case ID_POPUP_PCB_EDIT_ALL_VIAS_AND_TRACK_SIZE: if( GetCurItem() == NULL ) break; { int type = GetCurItem()->Type(); if( type == PCB_TRACE_T || type == PCB_VIA_T ) { BOARD_CONNECTED_ITEM*item = (BOARD_CONNECTED_ITEM*) GetCurItem(); DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS dlg( this, item->GetNetCode() ); dlg.ShowModal(); } } m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_BEGIN_TRACK: m_canvas->MoveCursorToCrossHair(); OnHotkeyBeginRoute( &dc ); break; case ID_POPUP_PCB_END_TRACK: m_canvas->MoveCursorToCrossHair(); End_Route( (TRACK*) GetCurItem(), &dc ); break; case ID_POPUP_PCB_PLACE_MOVED_TRACK_NODE: m_canvas->MoveCursorToCrossHair(); if( GetCurItem()->IsDragging() ) { PlaceDraggedOrMovedTrackSegment( (TRACK*) GetCurItem(), &dc ); } break; case ID_POPUP_PCB_SWITCH_TRACK_POSTURE: /* change the position of initial segment when creating new tracks * switch from _/ to -\ . * If a track is in progress, it will be redrawn */ if( m_canvas->IsMouseCaptured() ) m_canvas->CallMouseCapture( &dc, wxDefaultPosition, false ); g_Alternate_Track_Posture = !g_Alternate_Track_Posture; if( m_canvas->IsMouseCaptured() ) m_canvas->CallMouseCapture( &dc, wxDefaultPosition, false ); break; case ID_POPUP_PCB_PLACE_MICROVIA: if( !IsMicroViaAcceptable() ) break; // fall through case ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA: case ID_POPUP_PCB_PLACE_THROUGH_VIA: case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA: case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA: m_canvas->MoveCursorToCrossHair(); if( GetCurItem()->IsDragging() ) { PlaceDraggedOrMovedTrackSegment( (TRACK*) GetCurItem(), &dc ); } else { BOARD_DESIGN_SETTINGS &settings = GetDesignSettings(); VIATYPE_T v_type = settings.m_CurrentViaType; switch( id ) { case ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA: case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA: settings.m_CurrentViaType = VIA_BLIND_BURIED; break; case ID_POPUP_PCB_PLACE_MICROVIA: settings.m_CurrentViaType = VIA_MICROVIA; break; default: settings.m_CurrentViaType = VIA_THROUGH; break; } // place via and switch layer. if( id == ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA || id == ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA ) { m_canvas->SetIgnoreMouseEvents( true ); wxPoint dlgPosition; wxGetMousePosition( &dlgPosition.x, &dlgPosition.y ); LAYER_NUM layer = SelectLayer( getActiveLayer(), ALL_NO_CU_LAYERS, dlgPosition ); m_canvas->SetIgnoreMouseEvents( false ); m_canvas->MoveCursorToCrossHair(); if( getActiveLayer() != layer ) { GetScreen()->m_Route_Layer_TOP = getActiveLayer(); GetScreen()->m_Route_Layer_BOTTOM = layer; Other_Layer_Route( (TRACK*) GetCurItem(), &dc ); } } else Other_Layer_Route( (TRACK*) GetCurItem(), &dc ); settings.m_CurrentViaType = v_type; if( DisplayOpt.ContrastModeDisplay ) m_canvas->Refresh(); } break; case ID_POPUP_PCB_DELETE_TRACKSEG: if( GetCurItem() == NULL ) break; m_canvas->MoveCursorToCrossHair(); SetCurItem( Delete_Segment( &dc, (TRACK*) GetCurItem() ) ); OnModify(); break; case ID_POPUP_PCB_DELETE_TRACK: if( GetCurItem() == NULL ) break; m_canvas->MoveCursorToCrossHair(); Delete_Track( &dc, (TRACK*) GetCurItem() ); SetCurItem( NULL ); OnModify(); break; case ID_POPUP_PCB_DELETE_TRACKNET: m_canvas->MoveCursorToCrossHair(); Delete_net( &dc, (TRACK*) GetCurItem() ); SetCurItem( NULL ); OnModify(); break; case ID_POPUP_PCB_LOCK_ON_TRACKSEG: Attribut_Segment( (TRACK*) GetCurItem(), &dc, true ); break; case ID_POPUP_PCB_LOCK_OFF_TRACKSEG: Attribut_Segment( (TRACK*) GetCurItem(), &dc, false ); break; case ID_POPUP_PCB_LOCK_ON_TRACK: Attribut_Track( (TRACK*) GetCurItem(), &dc, true ); break; case ID_POPUP_PCB_LOCK_OFF_TRACK: Attribut_Track( (TRACK*) GetCurItem(), &dc, false ); break; case ID_POPUP_PCB_LOCK_ON_NET: Attribut_net( &dc, ( (TRACK*) GetCurItem() )->GetNetCode(), true ); break; case ID_POPUP_PCB_LOCK_OFF_NET: Attribut_net( &dc, ( (TRACK*) GetCurItem() )->GetNetCode(), false ); break; case ID_POPUP_PCB_SETFLAGS_TRACK_MNU: break; case ID_POPUP_PCB_DELETE_ZONE: m_canvas->MoveCursorToCrossHair(); if( GetCurItem() == NULL ) break; { SEGZONE* zsegm = (SEGZONE*) GetCurItem(); int netcode = zsegm->GetNetCode(); Delete_OldZone_Fill( zsegm ); SetCurItem( NULL ); TestNetConnection( NULL, netcode ); OnModify(); SetMsgPanel( GetBoard() ); } break; case ID_POPUP_PCB_EDIT_ZONE_PARAMS: Edit_Zone_Params( &dc, (ZONE_CONTAINER*) GetCurItem() ); SetCurItem( NULL ); // Outlines can have changed break; case ID_POPUP_PCB_ZONE_DUPLICATE: { ZONE_CONTAINER* zone = (ZONE_CONTAINER*) GetCurItem(); duplicateZone( &dc, zone ); } break; case ID_POPUP_PCB_ZONE_ADD_SIMILAR_ZONE: m_canvas->MoveCursorToCrossHair(); m_canvas->SetAutoPanRequest( true ); Add_Similar_Zone( &dc, (ZONE_CONTAINER*) GetCurItem() ); break; case ID_POPUP_PCB_ZONE_ADD_CUTOUT_ZONE: m_canvas->MoveCursorToCrossHair(); m_canvas->SetAutoPanRequest( true ); Add_Zone_Cutout( &dc, (ZONE_CONTAINER*) GetCurItem() ); break; case ID_POPUP_PCB_DELETE_ZONE_CONTAINER: case ID_POPUP_PCB_DELETE_ZONE_CUTOUT: m_canvas->MoveCursorToCrossHair(); { int netcode = ( (ZONE_CONTAINER*) GetCurItem() )->GetNetCode(); Delete_Zone_Contour( &dc, (ZONE_CONTAINER*) GetCurItem() ); SetCurItem( NULL ); TestNetConnection( NULL, netcode ); SetMsgPanel( GetBoard() ); } break; case ID_POPUP_PCB_DELETE_ZONE_CORNER: Remove_Zone_Corner( &dc, (ZONE_CONTAINER*) GetCurItem() ); SetCurItem( NULL ); break; case ID_POPUP_PCB_MOVE_ZONE_CORNER: { m_canvas->MoveCursorToCrossHair(); ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem(); m_canvas->SetAutoPanRequest( true ); Start_Move_Zone_Corner( &dc, zone_cont, zone_cont->GetSelectedCorner(), false ); break; } case ID_POPUP_PCB_DRAG_ZONE_OUTLINE_SEGMENT: { m_canvas->MoveCursorToCrossHair(); ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem(); m_canvas->SetAutoPanRequest( true ); Start_Move_Zone_Drag_Outline_Edge( &dc, zone_cont, zone_cont->GetSelectedCorner() ); break; } case ID_POPUP_PCB_MOVE_ZONE_OUTLINES: { m_canvas->MoveCursorToCrossHair(); ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem(); m_canvas->SetAutoPanRequest( true ); Start_Move_Zone_Outlines( &dc, zone_cont ); break; } case ID_POPUP_PCB_ADD_ZONE_CORNER: { m_canvas->MoveCursorToCrossHair(); ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem(); wxPoint pos = GetCrossHairPosition(); /* add corner between zone_cont->m_CornerSelection * and zone_cont->m_CornerSelection+1 * and start move the new corner */ zone_cont->Draw( m_canvas, &dc, GR_XOR ); zone_cont->Outline()->InsertCorner( zone_cont->GetSelectedCorner(), pos.x, pos.y ); zone_cont->SetSelectedCorner( zone_cont->GetSelectedCorner() + 1 ); zone_cont->Draw( m_canvas, &dc, GR_XOR ); m_canvas->SetAutoPanRequest( true ); Start_Move_Zone_Corner( &dc, zone_cont, zone_cont->GetSelectedCorner(), true ); break; } case ID_POPUP_PCB_PLACE_ZONE_OUTLINES: case ID_POPUP_PCB_PLACE_ZONE_CORNER: { m_canvas->MoveCursorToCrossHair(); ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem(); End_Move_Zone_Corner_Or_Outlines( &dc, zone_cont ); m_canvas->SetAutoPanRequest( false ); break; } case ID_POPUP_PCB_FILL_ALL_ZONES: m_canvas->MoveCursorToCrossHair(); Fill_All_Zones( this ); m_canvas->Refresh(); SetMsgPanel( GetBoard() ); break; case ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_CURRENT_ZONE: if( ( GetCurItem() )->Type() == PCB_ZONE_AREA_T ) { ZONE_CONTAINER* zone_container = (ZONE_CONTAINER*) GetCurItem(); zone_container->UnFill(); TestNetConnection( NULL, zone_container->GetNetCode() ); OnModify(); SetMsgPanel( GetBoard() ); m_canvas->Refresh(); } SetCurItem( NULL ); break; case ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_ALL_ZONES: // Remove all zones : GetBoard()->m_Zone.DeleteAll(); // remove zone segments used to fill zones. for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ ) { // Remove filled areas in zone ZONE_CONTAINER* zone_container = GetBoard()->GetArea( ii ); zone_container->ClearFilledPolysList(); } SetCurItem( NULL ); // CurItem might be deleted by this command, clear the pointer TestConnections(); TestForActiveLinksInRatsnest( 0 ); // Recalculate the active ratsnest, i.e. the unconnected links OnModify(); SetMsgPanel( GetBoard() ); m_canvas->Refresh(); break; case ID_POPUP_PCB_FILL_ZONE: m_canvas->MoveCursorToCrossHair(); Fill_Zone( (ZONE_CONTAINER*) GetCurItem() ); TestNetConnection( NULL, ( (ZONE_CONTAINER*) GetCurItem() )->GetNetCode() ); SetMsgPanel( GetBoard() ); m_canvas->Refresh(); break; case ID_POPUP_PCB_MOVE_TEXTEPCB_REQUEST: StartMoveTextePcb( (TEXTE_PCB*) GetCurItem(), &dc ); m_canvas->SetAutoPanRequest( true ); break; case ID_POPUP_PCB_DRAG_MODULE_REQUEST: case ID_POPUP_PCB_MOVE_MODULE_REQUEST: if( GetCurItem() == NULL ) break; // If the current Item is a pad, text module ...: Get its parent if( GetCurItem()->Type() != PCB_MODULE_T ) SetCurItem( GetCurItem()->GetParent() ); if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T ) break; module = (MODULE*) GetCurItem(); if( module->IsLocked() ) { wxString msg; msg.Printf( _( "Footprint %s found, but it is locked" ), module->GetReference().GetData() ); DisplayInfoMessage( this, msg ); break; } SendMessageToEESCHEMA( module ); SetCrossHairPosition( module->GetPosition() ); m_canvas->MoveCursorToCrossHair(); StartMoveModule( module, &dc, id == ID_POPUP_PCB_DRAG_MODULE_REQUEST ); break; case ID_POPUP_PCB_GET_AND_MOVE_MODULE_REQUEST: // get module by name and move it SetCurItem( GetModuleByName() ); module = (MODULE*) GetCurItem(); if( module == NULL ) break; if( module->IsLocked() ) { wxString msg = wxString::Format( _( "Footprint %s found, but it is locked" ), module->GetReference().GetData() ); DisplayInfoMessage( this, msg ); break; } SendMessageToEESCHEMA( module ); m_canvas->MoveCursorToCrossHair(); StartMoveModule( module, &dc, false ); break; case ID_POPUP_PCB_DELETE_MODULE: m_canvas->MoveCursorToCrossHair(); // If the current Item is a pad, text module ...: Get its parent if( GetCurItem()->Type() != PCB_MODULE_T ) SetCurItem( GetCurItem()->GetParent() ); if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T ) break; module = (MODULE*) GetCurItem(); if( module->IsLocked() ) { wxString msg; msg.Printf( _( "Footprint %s found, but it is locked" ), module->GetReference().GetData() ); DisplayInfoMessage( this, msg ); break; } if( Delete_Module( (MODULE*) GetCurItem(), &dc, true ) ) { SetCurItem( NULL ); } break; case ID_POPUP_PCB_ROTATE_MODULE_COUNTERCLOCKWISE: m_canvas->MoveCursorToCrossHair(); // If the current Item is a pad, text module ...: Get its parent if( GetCurItem()->Type() != PCB_MODULE_T ) SetCurItem( GetCurItem()->GetParent() ); if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T ) break; module = (MODULE*) GetCurItem(); if( module->IsLocked() ) { wxString msg; msg.Printf( _( "Footprint %s found, but it is locked" ), module->GetReference().GetData() ); DisplayInfoMessage( this, msg ); break; } // This is a simple rotation, no other editing in progress if( !GetCurItem()->IsMoving() ) SaveCopyInUndoList( GetCurItem(), UR_CHANGED, ((MODULE*)GetCurItem())->GetPosition() ); Rotate_Module( &dc, (MODULE*) GetCurItem(), m_rotationAngle, true ); break; case ID_POPUP_PCB_ROTATE_MODULE_CLOCKWISE: m_canvas->MoveCursorToCrossHair(); // If the current Item is a pad, text module ...: Get its parent if( GetCurItem()->Type() != PCB_MODULE_T ) SetCurItem( GetCurItem()->GetParent() ); if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T ) break; module = (MODULE*) GetCurItem(); if( module->IsLocked() ) { wxString msg; msg.Printf( _( "Footprint %s found, but it is locked" ), module->GetReference().GetData() ); DisplayInfoMessage( this, msg ); break; } // This is a simple rotation, no other editing in progress if( !GetCurItem()->IsMoving() ) SaveCopyInUndoList( GetCurItem(), UR_CHANGED, ((MODULE*)GetCurItem())->GetPosition() ); Rotate_Module( &dc, (MODULE*) GetCurItem(), -m_rotationAngle, true ); break; case ID_POPUP_PCB_CHANGE_SIDE_MODULE: m_canvas->MoveCursorToCrossHair(); // If the current Item is a pad, text module ...: Get its parent if( GetCurItem()->Type() != PCB_MODULE_T ) SetCurItem( GetCurItem()->GetParent() ); if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T ) break; module = (MODULE*) GetCurItem(); if( module->IsLocked() ) { wxString msg; msg.Printf( _( "Footprint %s found, but it is locked" ), module->GetReference().GetData() ); DisplayInfoMessage( this, msg ); break; } // This is a simple flip, no other editing in progress if( !GetCurItem()->IsMoving() ) SaveCopyInUndoList( GetCurItem(), UR_FLIPPED, ((MODULE*)GetCurItem())->GetPosition() ); Change_Side_Module( (MODULE*) GetCurItem(), &dc ); break; case ID_POPUP_PCB_EDIT_MODULE_PRMS: // If the current Item is a pad, text module ...: Get its parent if( GetCurItem()->Type() != PCB_MODULE_T ) SetCurItem( GetCurItem()->GetParent() ); if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T ) break; InstallModuleOptionsFrame( (MODULE*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_EDIT_MODULE_WITH_MODEDIT: // If the current Item is a pad, text module ...: Get its parent if( GetCurItem()->Type() != PCB_MODULE_T ) SetCurItem( GetCurItem()->GetParent() ); if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T ) break; if( GetCurItem()->GetTimeStamp() == 0 ) // Module Editor needs a non null timestamp { GetCurItem()->SetTimeStamp( GetNewTimeStamp() ); OnModify(); } { FOOTPRINT_EDIT_FRAME* editor = (FOOTPRINT_EDIT_FRAME*) Kiway().Player( FRAME_PCB_MODULE_EDITOR, true ); editor->Load_Module_From_BOARD( (MODULE*)GetCurItem() ); SetCurItem( NULL ); // the current module could be deleted by editor->Show( true ); editor->Raise(); // Iconize( false ); } m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_DRAG_PAD_REQUEST: module = (MODULE*) GetCurItem()->GetParent(); if( !module || module->Type() != PCB_MODULE_T ) break; if( module->IsLocked() ) { wxString msg; msg.Printf( _( "The parent (%s) of the pad is locked" ), module->GetReference().GetData() ); DisplayInfoMessage( this, msg ); break; } m_canvas->MoveCursorToCrossHair(); StartMovePad( (D_PAD*) GetCurItem(), &dc, true ); break; case ID_POPUP_PCB_MOVE_PAD_REQUEST: module = (MODULE*) GetCurItem()->GetParent(); if( !module || module->Type() != PCB_MODULE_T ) break; if( module->IsLocked() ) { wxString msg; msg.Printf( _( "The parent (%s) of the pad is locked" ), module->GetReference().GetData() ); DisplayInfoMessage( this, msg ); break; } m_canvas->MoveCursorToCrossHair(); StartMovePad( (D_PAD*) GetCurItem(), &dc, false ); break; case ID_POPUP_PCB_EDIT_PAD: InstallPadOptionsFrame( (D_PAD*) GetCurItem() ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_IMPORT_PAD_SETTINGS: m_canvas->MoveCursorToCrossHair(); SaveCopyInUndoList( GetCurItem()->GetParent(), UR_CHANGED ); Import_Pad_Settings( (D_PAD*) GetCurItem(), true ); break; case ID_POPUP_PCB_GLOBAL_IMPORT_PAD_SETTINGS: m_canvas->MoveCursorToCrossHair(); DlgGlobalChange_PadSettings( (D_PAD*) GetCurItem(), true ); break; case ID_POPUP_PCB_EXPORT_PAD_SETTINGS: m_canvas->MoveCursorToCrossHair(); Export_Pad_Settings( (D_PAD*) GetCurItem() ); break; case ID_POPUP_PCB_DELETE_PAD: SaveCopyInUndoList( GetCurItem()->GetParent(), UR_CHANGED ); DeletePad( (D_PAD*) GetCurItem() ); SetCurItem( NULL ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_EDIT_TEXTMODULE: InstallTextModOptionsFrame( (TEXTE_MODULE*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_RESET_TEXT_SIZE: ResetTextSize( GetCurItem(), &dc ); break; case ID_POPUP_PCB_MOVE_TEXTMODULE_REQUEST: m_canvas->MoveCursorToCrossHair(); StartMoveTexteModule( (TEXTE_MODULE*) GetCurItem(), &dc ); break; case ID_POPUP_PCB_ROTATE_TEXTMODULE: RotateTextModule( (TEXTE_MODULE*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_DELETE_TEXTMODULE: DeleteTextModule( (TEXTE_MODULE*) GetCurItem() ); SetCurItem( NULL ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_SELECT_LAYER: itmp = SelectLayer( getActiveLayer() ); if( itmp >= 0 ) { // if user changed colors and we are in high contrast mode, then redraw // because the PAD_SMD pads may change color. if( DisplayOpt.ContrastModeDisplay && getActiveLayer() != itmp ) { m_canvas->Refresh(); } setActiveLayer( itmp ); } m_canvas->MoveCursorToCrossHair(); break; case ID_AUX_TOOLBAR_PCB_SELECT_LAYER_PAIR: SelectCopperLayerPair(); break; case ID_POPUP_PCB_SELECT_NO_CU_LAYER: itmp = SelectLayer( getActiveLayer(), ALL_CU_LAYERS ); if( itmp >= 0 ) setActiveLayer( itmp ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_SELECT_CU_LAYER: itmp = SelectLayer( getActiveLayer(), ALL_NO_CU_LAYERS ); if( itmp >= 0 ) setActiveLayer( itmp ); break; case ID_POPUP_PCB_SELECT_LAYER_PAIR: SelectCopperLayerPair(); m_canvas->MoveCursorToCrossHair(); break; case ID_TOOLBARH_PCB_SELECT_LAYER: setActiveLayer( m_SelLayerBox->GetLayerSelection() ); if( DisplayOpt.ContrastModeDisplay ) m_canvas->Refresh( true ); break; case ID_POPUP_PCB_EDIT_TEXTEPCB: InstallTextPCBOptionsFrame( (TEXTE_PCB*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_ROTATE_TEXTEPCB: Rotate_Texte_Pcb( (TEXTE_PCB*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_COPY_TEXTEPCB: CreateTextePcb( &dc, (TEXTE_PCB*) GetCurItem() ); m_canvas->MoveCursorToCrossHair(); m_canvas->SetAutoPanRequest( true ); break; case ID_POPUP_PCB_FLIP_TEXTEPCB: FlipTextePcb( (TEXTE_PCB*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_DELETE_TEXTEPCB: Delete_Texte_Pcb( (TEXTE_PCB*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_MOVE_MIRE_REQUEST: BeginMoveTarget( (PCB_TARGET*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_EDIT_MIRE: ShowTargetOptionsDialog( (PCB_TARGET*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_DELETE_MIRE: m_canvas->MoveCursorToCrossHair(); DeleteTarget( (PCB_TARGET*) GetCurItem(), &dc ); SetCurItem( NULL ); break; case ID_POPUP_PCB_DELETE_DIMENSION: m_canvas->MoveCursorToCrossHair(); DeleteDimension( (DIMENSION*) GetCurItem(), &dc ); SetCurItem( NULL ); break; case ID_POPUP_PCB_EDIT_DIMENSION: ShowDimensionPropertyDialog( (DIMENSION*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_MOVE_TEXT_DIMENSION_REQUEST: BeginMoveDimensionText( (DIMENSION*) GetCurItem(), &dc ); break; case ID_POPUP_PCB_DELETE_DRAWING: Delete_Segment_Edge( (DRAWSEGMENT*) GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_DELETE_MARKER: RemoveStruct( GetCurItem(), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_GETINFO_MARKER: if( GetCurItem() && GetCurItem()->Type() == PCB_MARKER_T ) ( (MARKER_PCB*) GetCurItem() )->DisplayMarkerInfo( this ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_DELETE_DRAWING_LAYER: if( GetCurItem()->GetFlags() != 0 ) break; Delete_Drawings_All_Layer( GetCurItem()->GetLayer() ); SetCurItem( NULL ); m_canvas->MoveCursorToCrossHair(); m_canvas->Refresh(); break; case ID_POPUP_PCB_EDIT_DRAWING: #ifndef USE_WX_OVERLAY InstallGraphicItemPropertiesDialog( (DRAWSEGMENT*) GetCurItem(), &dc ); #else // #1277772 - Draw into dialog converted in refresh request InstallGraphicItemPropertiesDialog( (DRAWSEGMENT*) GetCurItem(), NULL ); m_canvas->Refresh(); #endif m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_MOVE_DRAWING_REQUEST: m_canvas->MoveCursorToCrossHair(); Start_Move_DrawItem( (DRAWSEGMENT*) GetCurItem(), &dc ); break; case ID_POPUP_PCB_STOP_CURRENT_DRAWING: m_canvas->MoveCursorToCrossHair(); if( GetCurItem() && (GetCurItem()->IsNew()) ) { End_Edge( (DRAWSEGMENT*) GetCurItem(), &dc ); SetCurItem( NULL ); } break; case ID_POPUP_PCB_STOP_CURRENT_EDGE_ZONE: m_canvas->MoveCursorToCrossHair(); if( GetCurItem() && (GetCurItem()->IsNew()) ) { if( End_Zone( &dc ) ) SetCurItem( NULL ); } m_canvas->SetAutoPanRequest( false ); break; case ID_POPUP_PCB_DELETE_ZONE_LAST_CREATED_CORNER: m_canvas->MoveCursorToCrossHair(); if( GetCurItem() && (GetCurItem()->IsNew()) ) { if( Delete_LastCreatedCorner( &dc ) == 0 ) // No more segment in outline, SetCurItem( NULL ); } break; case ID_POPUP_PCB_MOVE_TRACK_SEGMENT: m_canvas->MoveCursorToCrossHair(); StartMoveOneNodeOrSegment( (TRACK*) GetScreen()->GetCurItem(), &dc, id ); break; case ID_POPUP_PCB_DRAG_TRACK_SEGMENT: case ID_POPUP_PCB_MOVE_TRACK_NODE: m_canvas->MoveCursorToCrossHair(); StartMoveOneNodeOrSegment( (TRACK*) GetScreen()->GetCurItem(), &dc, id ); break; case ID_POPUP_PCB_DRAG_TRACK_SEGMENT_KEEP_SLOPE: m_canvas->MoveCursorToCrossHair(); Start_DragTrackSegmentAndKeepSlope( (TRACK*) GetScreen()->GetCurItem(), &dc ); break; case ID_POPUP_PCB_BREAK_TRACK: m_canvas->MoveCursorToCrossHair(); { TRACK* track = (TRACK*) GetScreen()->GetCurItem(); wxPoint pos = GetCrossHairPosition(); track->Draw( m_canvas, &dc, GR_XOR ); PICKED_ITEMS_LIST itemsListPicker; TRACK* newtrack = GetBoard()->CreateLockPoint( pos, track, &itemsListPicker ); SaveCopyInUndoList( itemsListPicker, UR_UNSPECIFIED ); track->Draw( m_canvas, &dc, GR_XOR ); newtrack->Draw( m_canvas, &dc, GR_XOR ); // compute the new ratsnest, because connectivity could change TestNetConnection( &dc, track->GetNetCode() ); } break; case ID_MENU_PCB_CLEAN: Clean_Pcb(); break; case ID_MENU_PCB_SWAP_LAYERS: Swap_Layers( event ); break; case ID_PCB_USER_GRID_SETUP: InvokeDialogGrid(); break; case ID_POPUP_PCB_DISPLAY_FOOTPRINT_DOC: { wxConfigBase* cfg = Pgm().CommonSettings(); cfg->Read( wxT( "module_doc_file" ), g_DocModulesFileName ); GetAssociatedDocument( this, g_DocModulesFileName, &Kiface().KifaceSearch() ); } break; case ID_MENU_ARCHIVE_NEW_MODULES: ArchiveModulesOnBoard( true ); break; case ID_MENU_ARCHIVE_ALL_MODULES: ArchiveModulesOnBoard( false ); break; case ID_GEN_IMPORT_DXF_FILE: InvokeDXFDialogImport( this ); m_canvas->Refresh(); break; default: wxString msg; msg.Printf( wxT( "PCB_EDIT_FRAME::Process_Special_Functions() unknown event id %d" ), id ); DisplayError( this, msg ); break; } m_canvas->CrossHairOn( &dc ); m_canvas->SetIgnoreMouseEvents( false ); }
/* Execute a remote command send by Eeschema via a socket, * port KICAD_PCB_PORT_SERVICE_NUMBER * cmdline = received command from Eeschema * Commands are * $PART: "reference" put cursor on component * $PIN: "pin name" $PART: "reference" put cursor on the footprint pin */ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) { char line[1024]; wxString msg; wxString modName; char* idcmd; char* text; MODULE* module = 0; BOARD* pcb = GetBoard(); wxPoint pos; strncpy( line, cmdline, sizeof(line) - 1 ); idcmd = strtok( line, " \n\r" ); text = strtok( NULL, " \n\r" ); if( !idcmd || !text ) return; if( strcmp( idcmd, "$PART:" ) == 0 ) { modName = FROM_UTF8( text ); module = pcb->FindModuleByReference( modName ); if( module ) msg.Printf( _( "%s found" ), GetChars( modName ) ); else msg.Printf( _( "%s not found" ), GetChars( modName ) ); SetStatusText( msg ); if( module ) pos = module->GetPosition(); } else if( strcmp( idcmd, "$PIN:" ) == 0 ) { wxString pinName; D_PAD* pad = NULL; int netcode = -1; pinName = FROM_UTF8( text ); text = strtok( NULL, " \n\r" ); if( text && strcmp( text, "$PART:" ) == 0 ) text = strtok( NULL, "\n\r" ); modName = FROM_UTF8( text ); module = pcb->FindModuleByReference( modName ); if( module ) pad = module->FindPadByName( pinName ); if( pad ) { netcode = pad->GetNetCode(); // put cursor on the pad: pos = pad->GetPosition(); } if( netcode > 0 ) // highlight the pad net { pcb->HighLightON(); pcb->SetHighLightNet( netcode ); } else { pcb->HighLightOFF(); pcb->SetHighLightNet( -1 ); } if( module == NULL ) { msg.Printf( _( "%s not found" ), GetChars( modName ) ); } else if( pad == NULL ) { msg.Printf( _( "%s pin %s not found" ), GetChars( modName ), GetChars( pinName ) ); SetCurItem( module ); } else { msg.Printf( _( "%s pin %s found" ), GetChars( modName ), GetChars( pinName ) ); SetCurItem( pad ); } SetStatusText( msg ); } if( module ) // if found, center the module on screen, and redraw the screen. { SetCrossHairPosition( pos ); RedrawScreen( pos, false ); } }
/* 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(); }
const EDA_RECT DRAWSEGMENT::GetBoundingBox() const { EDA_RECT bbox; bbox.SetOrigin( m_Start ); switch( m_Shape ) { case S_SEGMENT: bbox.SetEnd( m_End ); break; case S_CIRCLE: bbox.Inflate( GetRadius() ); break; case S_ARC: { bbox.Merge( m_End ); wxPoint end = m_End; RotatePoint( &end, m_Start, -m_Angle ); bbox.Merge( end ); } break; case S_POLYGON: { wxPoint p_end; MODULE* module = GetParentModule(); for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) { wxPoint pt = m_PolyPoints[ii]; if( module ) // Transform, if we belong to a module { RotatePoint( &pt, module->GetOrientation() ); pt += module->GetPosition(); } if( ii == 0 ) p_end = pt; bbox.SetX( std::min( bbox.GetX(), pt.x ) ); bbox.SetY( std::min( bbox.GetY(), pt.y ) ); p_end.x = std::max( p_end.x, pt.x ); p_end.y = std::max( p_end.y, pt.y ); } bbox.SetEnd( p_end ); } break; default: ; } bbox.Inflate( ((m_Width+1) / 2) + 1 ); bbox.Normalize(); return bbox; }
void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event ) { if( m_parent->GetBoard()->m_Modules == NULL ) { DisplayInfoMessage( this, _( "No footprints" ) ); return; } // Lists of duplicates, missing references and not in netlist footprints: std::vector <MODULE*> duplicate; wxArrayString missing; std::vector <MODULE*> notInNetlist; wxString netlistFilename = m_NetlistFilenameCtrl->GetValue(); if( !verifyFootprints( netlistFilename, wxEmptyString, duplicate, missing, notInNetlist ) ) return; #define ERR_CNT_MAX 100 // Max number of errors to output in dialog // to avoid a too long message list wxString list; // The messages to display m_parent->SetLastNetListRead( netlistFilename ); int err_cnt = 0; // Search for duplicate footprints. if( duplicate.size() == 0 ) list << wxT("<p><b>") << _( "No duplicate." ) << wxT("</b></p>"); else { list << wxT("<p><b>") << _( "Duplicates:" ) << wxT("</b></p>"); for( unsigned ii = 0; ii < duplicate.size(); ii++ ) { MODULE* module = duplicate[ii]; if( module->GetReference().IsEmpty() ) list << wxT("<br>") << wxT("[noref)"); else list << wxT("<br>") << module->GetReference(); list << wxT(" (<i>") << module->GetValue() << wxT("</i>)"); list << wxT(" @ "); list << CoordinateToString( module->GetPosition().x ), list << wxT(", ") << CoordinateToString( module->GetPosition().y ), err_cnt++; if( ERR_CNT_MAX < err_cnt ) break; } } // Search for missing modules on board. if( missing.size() == 0 ) list << wxT("<p><b>") << _( "No missing footprints." ) << wxT("</b></p>"); else { list << wxT("<p><b>") << _( "Missing:" ) << wxT("</b></p>"); for( unsigned ii = 0; ii < missing.size(); ii += 2 ) { list << wxT("<br>") << missing[ii]; list << wxT(" (<i>") << missing[ii+1] << wxT("</i>)"); err_cnt++; if( ERR_CNT_MAX < err_cnt ) break; } } // Search for modules found on board but not in net list. if( notInNetlist.size() == 0 ) list << wxT( "<p><b>" ) << _( "No extra footprints." ) << wxT( "</b></p>" ); else { list << wxT( "<p><b>" ) << _( "Not in Netlist:" ) << wxT( "</b></p>" ); for( unsigned ii = 0; ii < notInNetlist.size(); ii++ ) { MODULE* module = notInNetlist[ii]; if( module->GetReference().IsEmpty() ) list << wxT( "<br>" ) << wxT( "[noref)" ); else list << wxT( "<br>" ) << module->GetReference() ; list << wxT( " (<i>" ) << module->GetValue() << wxT( "</i>)" ); list << wxT( " @ " ); list << CoordinateToString( module->GetPosition().x ), list << wxT( ", " ) << CoordinateToString( module->GetPosition().y ), err_cnt++; if( ERR_CNT_MAX < err_cnt ) break; } } if( ERR_CNT_MAX < err_cnt ) { list << wxT( "<p><b>" ) << _( "Too many errors: some are skipped" ) << wxT( "</b></p>" ); } HTML_MESSAGE_BOX dlg( this, _( "Check footprints" ) ); dlg.AddHTML_Text( list ); dlg.ShowModal(); }
int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent ) { MODULE* module = NULL; KIGFX::VIEW* view = getView(); KIGFX::VIEW_CONTROLS* controls = getViewControls(); BOARD* board = getModel<BOARD>(); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( view ); view->Add( &preview ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); controls->ShowCursor( true ); controls->SetSnapping( true ); controls->SetAutoPan( true ); controls->CaptureCursor( true ); Activate(); m_frame->SetToolID( ID_PCB_MODULE_BUTT, wxCURSOR_HAND, _( "Add module" ) ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { VECTOR2I cursorPos = controls->GetCursorPosition(); if( evt->IsCancel() || evt->IsActivate() ) { if( module ) { board->Delete( module ); // it was added by LoadModuleFromLibrary() module = NULL; preview.Clear(); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); controls->ShowCursor( true ); } else break; if( evt->IsActivate() ) // now finish unconditionally break; } else if( module && evt->Category() == TC_COMMAND ) { if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { module->Rotate( module->GetPosition(), m_frame->GetRotationAngle() ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) { module->Flip( module->GetPosition() ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } else if( evt->IsClick( BUT_LEFT ) ) { if( !module ) { // Init the new item attributes module = m_frame->LoadModuleFromLibrary( wxEmptyString, m_frame->Prj().PcbFootprintLibs(), true, NULL ); if( module == NULL ) continue; controls->ShowCursor( false ); module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); // Add all the drawable parts to preview preview.Add( module ); module->RunOnChildren( boost::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else { module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); view->Add( module ); module->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_frame->OnModify(); m_frame->SaveCopyInUndoList( module, UR_NEW ); // Remove from preview preview.Remove( module ); module->RunOnChildren( boost::bind( &KIGFX::VIEW_GROUP::Remove, &preview, _1 ) ); module = NULL; // to indicate that there is no module that we currently modify controls->ShowCursor( true ); } } else if( module && evt->IsMotion() ) { module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } controls->ShowCursor( false ); controls->SetSnapping( false ); controls->SetAutoPan( false ); controls->CaptureCursor( false ); view->Remove( &preview ); setTransitions(); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
/* Driver function: processing starts here */ void PCB_EDIT_FRAME::ExportToGenCAD( wxCommandEvent& aEvent ) { wxFileName fn = GetBoard()->GetFileName(); FILE* file; wxString ext = wxT( "cad" ); wxString wildcard = _( "GenCAD 1.4 board files (.cad)|*.cad" ); fn.SetExt( ext ); wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() ); wxFileDialog dlg( this, _( "Save GenCAD Board File" ), pro_dir, fn.GetFullName(), wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if( dlg.ShowModal() == wxID_CANCEL ) return; if( ( file = wxFopen( dlg.GetPath(), wxT( "wt" ) ) ) == NULL ) { wxString msg; msg.Printf( _( "Unable to create <%s>" ), GetChars( dlg.GetPath() ) ); DisplayError( this, msg ); return; } SetLocaleTo_C_standard(); // No pesky decimal separators in gencad // Update some board data, to ensure a reliable gencad export GetBoard()->ComputeBoundingBox(); // Save the auxiliary origin for the rest of the module GencadOffsetX = GetAuxOrigin().x; GencadOffsetY = GetAuxOrigin().y; // No idea on *why* this should be needed... maybe to fix net names? Compile_Ratsnest( NULL, true ); /* Temporary modification of footprints that are flipped (i.e. on bottom * layer) to convert them to non flipped footprints. * This is necessary to easily export shapes to GenCAD, * that are given as normal orientation (non flipped, rotation = 0)) * these changes will be undone later */ BOARD* pcb = GetBoard(); MODULE* module; for( module = pcb->m_Modules; module; module = module->Next() ) { module->SetFlag( 0 ); if( module->GetLayer() == B_Cu ) { module->Flip( module->GetPosition() ); module->SetFlag( 1 ); } } /* Gencad has some mandatory and some optional sections: some importer * need the padstack section (which is optional) anyway. Also the * order of the section *is* important */ CreateHeaderInfoData( file, this ); // Gencad header CreateBoardSection( file, pcb ); // Board perimeter CreatePadsShapesSection( file, pcb ); // Pads and padstacks CreateArtworksSection( file ); // Empty but mandatory /* Gencad splits a component info in shape, component and device. * We don't do any sharing (it would be difficult since each module is * customizable after placement) */ CreateShapesSection( file, pcb ); CreateComponentsSection( file, pcb ); CreateDevicesSection( file, pcb ); // In a similar way the netlist is split in net, track and route CreateSignalsSection( file, pcb ); CreateTracksInfoData( file, pcb ); CreateRoutesSection( file, pcb ); fclose( file ); SetLocaleTo_Default(); // revert to the current locale // Undo the footprints modifications (flipped footprints) for( module = pcb->m_Modules; module; module = module->Next() ) { if( module->GetFlag() ) { module->Flip( module->GetPosition() ); module->SetFlag( 0 ); } } }
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; }
/* Creates the section $COMPONENTS (Footprints placement) * Bottom side components are difficult to handle: shapes must be mirrored or * flipped, silk layers need to be handled correctly and so on. Also it seems * that *noone* follows the specs... */ static void CreateComponentsSection( FILE* aFile, BOARD* aPcb ) { fputs( "$COMPONENTS\n", aFile ); int cu_count = aPcb->GetCopperLayerCount(); for( MODULE* module = aPcb->m_Modules; module; module = module->Next() ) { const char* mirror; const char* flip; double fp_orient = module->GetOrientation(); if( module->GetFlag() ) { mirror = "0"; flip = "FLIP"; NEGATE_AND_NORMALIZE_ANGLE_POS( fp_orient ); } else { mirror = "0"; flip = "0"; } fprintf( aFile, "\nCOMPONENT %s\n", TO_UTF8( module->GetReference() ) ); fprintf( aFile, "DEVICE %s_%s\n", TO_UTF8( module->GetReference() ), TO_UTF8( module->GetValue() ) ); fprintf( aFile, "PLACE %g %g\n", MapXTo( module->GetPosition().x ), MapYTo( module->GetPosition().y ) ); fprintf( aFile, "LAYER %s\n", (module->GetFlag()) ? "BOTTOM" : "TOP" ); fprintf( aFile, "ROTATION %g\n", fp_orient / 10.0 ); fprintf( aFile, "SHAPE %s %s %s\n", TO_UTF8( module->GetReference() ), mirror, flip ); // Text on silk layer: RefDes and value (are they actually useful?) TEXTE_MODULE *textmod = &module->Reference(); for( int ii = 0; ii < 2; ii++ ) { double txt_orient = textmod->GetOrientation(); std::string layer = GenCADLayerName( cu_count, module->GetFlag() ? B_SilkS : F_SilkS ); fprintf( aFile, "TEXT %g %g %g %g %s %s \"%s\"", textmod->GetPos0().x / SCALE_FACTOR, -textmod->GetPos0().y / SCALE_FACTOR, textmod->GetSize().x / SCALE_FACTOR, txt_orient / 10.0, mirror, layer.c_str(), TO_UTF8( textmod->GetText() ) ); // Please note, the width is approx fprintf( aFile, " 0 0 %g %g\n", ( textmod->GetSize().x * textmod->GetLength() ) / SCALE_FACTOR, textmod->GetSize().y / SCALE_FACTOR ); textmod = &module->Value(); // Dirty trick for the second iteration } // The SHEET is a 'generic description' for referencing the component fprintf( aFile, "SHEET \"RefDes: %s, Value: %s\"\n", TO_UTF8( module->GetReference() ), TO_UTF8( module->GetValue() ) ); } fputs( "$ENDCOMPONENTS\n\n", aFile ); }
MODULE* PCB_BASE_FRAME::LoadModuleFromLibrary( const wxString& aLibrary, FP_LIB_TABLE* aTable, bool aUseFootprintViewer, wxDC* aDC ) { MODULE* module = NULL; wxPoint curspos = GetCrossHairPosition(); wxString moduleName, keys; wxString libName = aLibrary; bool allowWildSeach = true; static wxArrayString HistoryList; static wxString lastComponentName; // Ask for a component name or key words DIALOG_GET_COMPONENT dlg( this, HistoryList, _( "Load Footprint" ), aUseFootprintViewer ); dlg.SetComponentName( lastComponentName ); if( dlg.ShowModal() == wxID_CANCEL ) return NULL; if( dlg.m_GetExtraFunction ) { // SelectFootprintFromLibBrowser() returns the "full" footprint name, i.e. // <lib_name>/<footprint name> or FPID format "lib_name:fp_name:rev#" moduleName = SelectFootprintFromLibBrowser(); } else { moduleName = dlg.GetComponentName(); } if( moduleName.IsEmpty() ) // Cancel command { m_canvas->MoveCursorToCrossHair(); return NULL; } if( dlg.IsKeyword() ) // Selection by keywords { allowWildSeach = false; keys = moduleName; moduleName = SelectFootprint( this, libName, wxEmptyString, keys, aTable ); if( moduleName.IsEmpty() ) // Cancel command { m_canvas->MoveCursorToCrossHair(); return NULL; } } else if( moduleName.Contains( wxT( "?" ) ) || moduleName.Contains( wxT( "*" ) ) ) // Selection wild card { allowWildSeach = false; moduleName = SelectFootprint( this, libName, moduleName, wxEmptyString, aTable ); if( moduleName.IsEmpty() ) { m_canvas->MoveCursorToCrossHair(); return NULL; // Cancel command. } } FPID fpid; wxCHECK_MSG( fpid.Parse( moduleName ) < 0, NULL, wxString::Format( wxT( "Could not parse FPID string '%s'." ), GetChars( moduleName ) ) ); try { module = loadFootprint( fpid ); } catch( const IO_ERROR& ioe ) { wxLogDebug( wxT( "An error occurred attemping to load footprint '%s'.\n\nError: %s" ), fpid.Format().c_str(), GetChars( ioe.errorText ) ); } if( !module && allowWildSeach ) // Search with wild card { allowWildSeach = false; wxString wildname = wxChar( '*' ) + moduleName + wxChar( '*' ); moduleName = wildname; moduleName = SelectFootprint( this, libName, moduleName, wxEmptyString, aTable ); if( moduleName.IsEmpty() ) { m_canvas->MoveCursorToCrossHair(); return NULL; // Cancel command. } else { FPID fpid; wxCHECK_MSG( fpid.Parse( moduleName ) < 0, NULL, wxString::Format( wxT( "Could not parse FPID string '%s'." ), GetChars( moduleName ) ) ); try { module = loadFootprint( fpid ); } catch( const IO_ERROR& ioe ) { wxLogDebug( wxT( "An error occurred attemping to load footprint '%s'.\n\nError: %s" ), fpid.Format().c_str(), GetChars( ioe.errorText ) ); } } } SetCrossHairPosition( curspos ); m_canvas->MoveCursorToCrossHair(); if( module ) { GetBoard()->Add( module, ADD_APPEND ); lastComponentName = moduleName; AddHistoryComponentName( HistoryList, moduleName ); module->SetFlags( IS_NEW ); module->SetLink( 0 ); if( IsGalCanvasActive() ) module->SetPosition( wxPoint( 0, 0 ) ); // cursor in GAL may not be initialized at the moment else module->SetPosition( curspos ); module->SetTimeStamp( GetNewTimeStamp() ); GetBoard()->m_Status_Pcb = 0; // Put it on FRONT layer, // (Can be stored flipped if the lib is an archive built from a board) if( module->IsFlipped() ) module->Flip( module->GetPosition() ); // Place it in orientation 0, // even if it is not saved with orientation 0 in lib // (Can happen if the lib is an archive built from a board) Rotate_Module( NULL, module, 0, false ); RecalculateAllTracksNetcode(); if( aDC ) module->Draw( m_canvas, aDC, GR_OR ); } return module; }
bool FOOTPRINT_EDIT_FRAME::Load_Module_From_BOARD( MODULE* aModule ) { MODULE* newModule; PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) Kiway().Player( FRAME_PCB, false ); if( frame == NULL ) // happens if no board editor opened return false; if( aModule == NULL ) { if( ! frame->GetBoard() || ! frame->GetBoard()->m_Modules ) return false; aModule = SelectFootprint( frame->GetBoard() ); } if( aModule == NULL ) return false; SetCurItem( NULL ); Clear_Pcb( false ); GetBoard()->m_Status_Pcb = 0; newModule = new MODULE( *aModule ); newModule->SetParent( GetBoard() ); newModule->SetLink( aModule->GetTimeStamp() ); aModule = newModule; GetBoard()->Add( newModule ); newModule->ClearFlags(); // Clear references to net info, because the footprint editor // does know any thing about nets handled by the current edited board. // Morever the main board can change or the net info relative to this main board // can change while editing this footprint in the footprint editor for( D_PAD* pad = newModule->Pads(); pad; pad = pad->Next() ) pad->SetNetCode( NETINFO_LIST::UNCONNECTED ); SetCrossHairPosition( wxPoint( 0, 0 ) ); PlaceModule( newModule, NULL ); newModule->SetPosition( wxPoint( 0, 0 ) ); // cursor in GAL may not be initialized at the moment // Put it on FRONT layer, // because this is the default in ModEdit, and in libs if( newModule->GetLayer() != F_Cu ) newModule->Flip( newModule->GetPosition() ); // Put it in orientation 0, // because this is the default orientation in ModEdit, and in libs Rotate_Module( NULL, newModule, 0, false ); GetScreen()->ClrModify(); Zoom_Automatique( false ); if( IsGalCanvasActive() ) updateView(); return true; }
void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos ) { VECTOR2I origin; switch( aItem->Type() ) { case PCB_MODULE_T: { MODULE* mod = static_cast<MODULE*>( aItem ); addAnchor( mod->GetPosition(), ORIGIN | SNAPPABLE, mod ); for( D_PAD* pad = mod->Pads(); pad; pad = pad->Next() ) addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad ); break; } case PCB_PAD_T: { D_PAD* pad = static_cast<D_PAD*>( aItem ); addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad ); break; } case PCB_MODULE_EDGE_T: case PCB_LINE_T: { DRAWSEGMENT* dseg = static_cast<DRAWSEGMENT*>( aItem ); VECTOR2I start = dseg->GetStart(); VECTOR2I end = dseg->GetEnd(); //LAYER_ID layer = dseg->GetLayer(); switch( dseg->GetShape() ) { case S_CIRCLE: { int r = ( start - end ).EuclideanNorm(); addAnchor( start, ORIGIN | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, dseg ); break; } case S_ARC: { origin = dseg->GetCenter(); addAnchor( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg ); addAnchor( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg ); addAnchor( origin, ORIGIN | SNAPPABLE, dseg ); break; } case S_SEGMENT: { origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor( start, CORNER | SNAPPABLE, dseg ); addAnchor( end, CORNER | SNAPPABLE, dseg ); addAnchor( origin, ORIGIN, dseg ); break; } default: { origin = dseg->GetStart(); addAnchor( origin, ORIGIN | SNAPPABLE, dseg ); break; } } break; } case PCB_TRACE_T: { TRACK* track = static_cast<TRACK*>( aItem ); VECTOR2I start = track->GetStart(); VECTOR2I end = track->GetEnd(); origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor( start, CORNER | SNAPPABLE, track ); addAnchor( end, CORNER | SNAPPABLE, track ); addAnchor( origin, ORIGIN, track); break; } case PCB_VIA_T: addAnchor( aItem->GetPosition(), CORNER | SNAPPABLE, aItem ); break; case PCB_ZONE_AREA_T: { const CPolyLine* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline(); int cornersCount = outline->GetCornersCount(); SHAPE_LINE_CHAIN lc; lc.SetClosed( true ); for( int i = 0; i < cornersCount; ++i ) { const VECTOR2I p ( outline->GetPos( i ) ); addAnchor( p, CORNER, aItem ); lc.Append( p ); } addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem ); break; } case PCB_MODULE_TEXT_T: case PCB_TEXT_T: addAnchor( aItem->GetPosition(), ORIGIN, aItem ); default: break; } }
bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() { BOARD_COMMIT commit( m_parent ); 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 return false; commit.Modify( m_currentPad ); wxSize size; MODULE* footprint = m_currentPad->GetParent(); 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() ); commit.Push( _( "Modify pad" ) ); if( rastnestIsChanged ) // The net ratsnest must be recalculated m_board->m_Status_Pcb = 0; return true; }