// Redraw the moved node according to the mouse cursor position static void Show_MoveNode( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { auto displ_opts = (PCB_DISPLAY_OPTIONS*) aPanel->GetDisplayOptions(); wxPoint moveVector; int tmp = displ_opts->m_DisplayPcbTrackFill; GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT; displ_opts->m_DisplayPcbTrackFill = false; #ifndef USE_WX_OVERLAY aErase = true; #else aErase = false; #endif // set the new track coordinates wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition(); moveVector = Pos - s_LastPos; s_LastPos = Pos; TRACK *track = NULL; for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ ) { track = g_DragSegmentList[ii].m_Track; if( aErase ) track->Draw( aPanel, aDC, draw_mode ); if( track->GetFlags() & STARTPOINT ) track->SetStart( track->GetStart() + moveVector ); if( track->GetFlags() & ENDPOINT ) track->SetEnd( track->GetEnd() + moveVector ); if( track->Type() == PCB_VIA_T ) track->SetEnd( track->GetStart() ); track->Draw( aPanel, aDC, draw_mode ); } displ_opts->m_DisplayPcbTrackFill = tmp; // Display track length if( track ) { PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent(); frame->SetMsgPanel( track ); } }
/* Init variables (slope, Y intersect point, flags) for * Show_Drag_Track_Segment_With_Cte_Slope() * return true if Ok, false if dragging is not possible * (2 colinear segments) */ bool InitialiseDragParameters() { double tx1, tx2, ty1, ty2; // temporary storage of points TRACK* Track; TRACK* tSegmentToStart = NULL, * tSegmentToEnd = NULL; if( g_DragSegmentList.size() == 0 ) return false; /* get the segments : * from last to first in list are: * the segment to move * the segment connected to its end point (if exists) * the segment connected to its start point (if exists) */ int ii = g_DragSegmentList.size() - 1; Track = g_DragSegmentList[ii].m_Track; if( Track == NULL ) return false; ii--; if( ii >= 0) { if( s_EndSegmentPresent ) { tSegmentToEnd = g_DragSegmentList[ii].m_Track; // Get the segment connected to // the end point ii--; } if( s_StartSegmentPresent ) { if( ii >= 0 ) tSegmentToStart = g_DragSegmentList[ii].m_Track; // Get the segment connected to // the start point } } // would be nice to eliminate collinear segments here, so we don't // have to deal with that annoying "Unable to drag this segment: two // collinear segments" s_StartPointVertical = false; s_EndPointVertical = false; s_MovingSegmentVertical = false; s_StartPointHorizontal = false; s_EndPointHorizontal = false; s_MovingSegmentHorizontal = false; // Init parameters for the starting point of the moved segment if( tSegmentToStart ) { if( tSegmentToStart->GetFlags() & ENDPOINT ) { tx1 = (double) tSegmentToStart->GetStart().x; ty1 = (double) tSegmentToStart->GetStart().y; tx2 = (double) tSegmentToStart->GetEnd().x; ty2 = (double) tSegmentToStart->GetEnd().y; } else { tx1 = (double) tSegmentToStart->GetEnd().x; ty1 = (double) tSegmentToStart->GetEnd().y; tx2 = (double) tSegmentToStart->GetStart().x; ty2 = (double) tSegmentToStart->GetStart().y; } } else // move the start point on a line starting at Track->GetStart(), and perpendicular to Track { tx1 = (double) Track->GetStart().x; ty1 = (double) Track->GetStart().y; tx2 = (double) Track->GetEnd().x; ty2 = (double) Track->GetEnd().y; RotatePoint( &tx2, &ty2, tx1, ty1, 900 ); } if( tx1 != tx2 ) { s_StartSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 ); s_StartSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 ); } else { s_StartPointVertical = true; //signal first segment vertical } if( ty1 == ty2 ) { s_StartPointHorizontal = true; } // Init parameters for the ending point of the moved segment if( tSegmentToEnd ) { //check if second line is vertical if( tSegmentToEnd->GetFlags() & STARTPOINT ) { tx1 = (double) tSegmentToEnd->GetStart().x; ty1 = (double) tSegmentToEnd->GetStart().y; tx2 = (double) tSegmentToEnd->GetEnd().x; ty2 = (double) tSegmentToEnd->GetEnd().y; } else { tx1 = (double) tSegmentToEnd->GetEnd().x; ty1 = (double) tSegmentToEnd->GetEnd().y; tx2 = (double) tSegmentToEnd->GetStart().x; ty2 = (double) tSegmentToEnd->GetStart().y; } } else // move the start point on a line starting at Track->GetEnd(), and perpendicular to Track { tx1 = (double) Track->GetEnd().x; ty1 = (double) Track->GetEnd().y; tx2 = (double) Track->GetStart().x; ty2 = (double) Track->GetStart().y; RotatePoint( &tx2, &ty2, tx1, ty1, -900 ); } if( tx2 != tx1 ) { s_EndSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 ); s_EndSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 ); } else { s_EndPointVertical = true; //signal second segment vertical } if( ty1 == ty2 ) { s_EndPointHorizontal = true; } // Init parameters for the moved segment tx1 = (double) Track->GetStart().x; ty1 = (double) Track->GetStart().y; tx2 = (double) Track->GetEnd().x; ty2 = (double) Track->GetEnd().y; if( tx2 != tx1 ) { s_MovingSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 ); } else { s_MovingSegmentVertical = true; // signal vertical line } if( ty1 == ty2 ) { s_MovingSegmentHorizontal = true; } // Test if drag is possible: if( s_MovingSegmentVertical ) { if( s_EndPointVertical || s_StartPointVertical ) return false; } else { if( !s_EndPointVertical && ( s_MovingSegmentSlope == s_EndSegmentSlope ) ) return false; if( !s_StartPointVertical && ( s_MovingSegmentSlope == s_StartSegmentSlope ) ) return false; } return true; }
/* drawing the track segment movement * > s_MovingSegmentSlope slope = moving track segment slope * > s_StartSegmentSlope slope = slope of the segment connected to the start * point of the moving segment * > s_EndSegmentSlope slope = slope of the segment connected to the end point * of the moving segment * * moved segment function : * yt=s_MovingSegmentSlope * x + s_MovingSegment_Yorg * * segment connected to moved segment's start: * y1 = s_StartSegmentSlope * x + s_StartSegment_Yorg * * segment connected to moved segment's end: * y2=s_EndSegmentSlope * x + s_EndSegment_Yorg * * first intersection point will be located at * y1=yt -> * * xi1=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_StartSegmentSlope-s_MovingSegmentSlope) * yi1=s_MovingSegmentSlope*xi1+s_MovingSegment_Yorg * or yi1=s_StartSegmentSlope*xi1+s_MovingSegment_Yorg * * second intersection point * y2=yt -> * * xi2=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_MovingSegmentSlope-s_MovingSegmentSlope) * yi2=s_MovingSegmentSlope*xi2+s_MovingSegment_Yorg * or yi1=s_EndSegmentSlope*xi2+s_MovingSegment_Yorg * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * !!!!! special attention to vertical segments because * !!!!! their slope=infinite * !!!!! intersection point will be calculated using the * !!!!! segment intersecting it * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * * Slope parameters are computed once, because they can become undetermined * when moving segments * (i.e. when a segment length is 0) and we want keep them constant */ static void Show_Drag_Track_Segment_With_Cte_Slope( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { double xi1 = 0, yi1 = 0, xi2 = 0, yi2 = 0; // calculated intersection points double tx1, tx2, ty1, ty2; // temporary storage of points int dx, dy; bool update = true; TRACK* Track; TRACK* tSegmentToStart = NULL, * tSegmentToEnd = NULL; if( g_DragSegmentList.size() == 0 ) return; /* get the segments : * from last to first in list are: * the segment to move * the segment connected to its end point (if exists) * the segment connected to its start point (if exists) */ int ii = g_DragSegmentList.size() - 1; Track = g_DragSegmentList[ii].m_Track; if( Track == NULL ) return; ii--; if( ii >= 0) { if( s_EndSegmentPresent ) { // Get the segment connected to the end point tSegmentToEnd = g_DragSegmentList[ii].m_Track; ii--; } if( s_StartSegmentPresent ) { // Get the segment connected to the start point if( ii >= 0 ) tSegmentToStart = g_DragSegmentList[ii].m_Track; } } GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT; // Undraw the current moved track segments before modification #ifndef USE_WX_OVERLAY // if( erase ) { Track->Draw( aPanel, aDC, draw_mode ); if( tSegmentToStart ) tSegmentToStart->Draw( aPanel, aDC, draw_mode ); if( tSegmentToEnd ) tSegmentToEnd->Draw( aPanel, aDC, draw_mode ); } #endif // Compute the new track segment position wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition(); dx = Pos.x - s_LastPos.x; dy = Pos.y - s_LastPos.y; // move the line by dx and dy tx1 = (double) ( Track->GetStart().x + dx ); ty1 = (double) ( Track->GetStart().y + dy ); tx2 = (double) ( Track->GetEnd().x + dx ); ty2 = (double) ( Track->GetEnd().y + dy ); // recalculate the segments new parameters and intersection points // only the intercept will change, segment slopes does not change // because we are moving parallel with is initial state if( !s_MovingSegmentVertical ) { s_MovingSegment_Yorg = ty1 - ( s_MovingSegmentSlope * tx1 ); } if( ( !s_EndPointVertical ) && ( !s_MovingSegmentVertical ) ) { xi2 = ( s_MovingSegment_Yorg - s_EndSegment_Yorg ) / ( s_EndSegmentSlope - s_MovingSegmentSlope ); } else { if( !s_EndPointVertical ) { xi2 = tx2; } else { //P1=P2 if( !s_EndPointHorizontal ) { xi2 = tx2 - dx; } else { update = false; } } } if( !s_MovingSegmentVertical ) { yi2 = s_MovingSegmentSlope * ( xi2 ) + s_MovingSegment_Yorg; } else { if( !s_EndPointVertical ) { yi2 = s_EndSegmentSlope * ( xi2 ) + s_EndSegment_Yorg; } else { if( !s_EndPointHorizontal ) { update = false; } else { yi2 = s_MovingSegmentSlope * ( xi2 ) + s_MovingSegment_Yorg; } } } if( ( !s_StartPointVertical ) && ( !s_MovingSegmentVertical ) ) { xi1 = ( s_MovingSegment_Yorg - s_StartSegment_Yorg ) / ( s_StartSegmentSlope - s_MovingSegmentSlope ); } else { if( !s_StartPointVertical ) { xi1 = tx1; } else { //P1=P2 if( !s_StartPointHorizontal ) { xi1 = tx1 - dx; } else { if( !s_StartPointHorizontal ) { update = false; } } } } if( !s_MovingSegmentVertical ) { yi1 = s_MovingSegmentSlope * ( xi1 ) + s_MovingSegment_Yorg; } else { if( !s_StartPointVertical ) { yi1 = s_StartSegmentSlope * ( xi1 ) + s_StartSegment_Yorg; } else { if( !s_StartPointHorizontal ) { update = false; } else { yi2 = s_MovingSegmentSlope * ( xi1 ) + s_MovingSegment_Yorg; } } } // update the segment coordinates (if possible) if( tSegmentToStart == NULL ) { xi1 = tx1; yi1 = ty1; } if( tSegmentToEnd == NULL ) { xi2 = tx2; yi2 = ty2; } if( update ) { s_LastPos = Pos; Track->SetStart( wxPoint( KiROUND( xi1 ), KiROUND( yi1 ) ) ); Track->SetEnd( wxPoint( KiROUND( xi2 ), KiROUND( yi2 ) ) ); if( tSegmentToEnd ) { if( tSegmentToEnd->GetFlags() & STARTPOINT ) tSegmentToEnd->SetStart( Track->GetEnd() ); else tSegmentToEnd->SetEnd( Track->GetEnd() ); } if( tSegmentToStart ) { if( tSegmentToStart->GetFlags() & STARTPOINT ) tSegmentToStart->SetStart( Track->GetStart() ); else tSegmentToStart->SetEnd( Track->GetStart() ); } } Track->Draw( aPanel, aDC, draw_mode ); if( tSegmentToStart ) tSegmentToStart->Draw( aPanel, aDC, draw_mode ); if( tSegmentToEnd ) tSegmentToEnd->Draw( aPanel, aDC, draw_mode ); // Display track length PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent(); frame->SetMsgPanel( Track ); }
int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) { int open_ctl; wxString fileName; PICKED_ITEMS_LIST undoListPicker; ITEM_PICKER picker( NULL, UR_NEW ); PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ); BOARD* board = getModel<BOARD>(); KIGFX::VIEW* view = getView(); if( !editFrame ) return 0; // Pick a file to append if( !AskLoadBoardFileName( editFrame, &open_ctl, &fileName, true ) ) return 0; IO_MGR::PCB_FILE_T pluginType = plugin_type( fileName, open_ctl ); PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); // keep track of existing items, in order to know what are the new items // (for undo command for instance) // Tracks are inserted, not appended, so mark the existing tracks to know what are the new tracks for( TRACK* track = board->m_Track; track; track = track->Next() ) track->SetFlags( FLAG0 ); // Other items are appended to the item list, so keep trace to the last existing item is enough MODULE* module = board->m_Modules.GetLast(); BOARD_ITEM* drawing = board->m_Drawings.GetLast(); int zonescount = board->GetAreaCount(); // Keep also the count of copper layers, to adjust if necessary int initialCopperLayerCount = board->GetCopperLayerCount(); LSET initialEnabledLayers = board->GetEnabledLayers(); // Load the data try { PROPERTIES props; char xbuf[30]; char ybuf[30]; // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet. sprintf( xbuf, "%d", editFrame->GetPageSizeIU().x ); sprintf( ybuf, "%d", editFrame->GetPageSizeIU().y ); props["page_width"] = xbuf; props["page_height"] = ybuf; editFrame->GetDesignSettings().m_NetClasses.Clear(); pi->Load( fileName, board, &props ); } catch( const IO_ERROR& ioe ) { wxString msg = wxString::Format( _( "Error loading board.\n%s" ), GetChars( ioe.errorText )); DisplayError( editFrame, msg ); return 0; } m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); // Process the new items for( TRACK* track = board->m_Track; track; track = track->Next() ) { if( track->GetFlags() & FLAG0 ) { track->ClearFlags( FLAG0 ); continue; } picker.SetItem( track ); undoListPicker.PushItem( picker ); view->Add( track ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, track ); } module = module ? module->Next() : board->m_Modules; for( ; module; module = module->Next() ) { picker.SetItem( module ); undoListPicker.PushItem( picker ); module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); view->Add( module ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, module ); } drawing = drawing ? drawing->Next() : board->m_Drawings; for( ; drawing; drawing = drawing->Next() ) { picker.SetItem( drawing ); undoListPicker.PushItem( picker ); view->Add( drawing ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, drawing ); } for( ZONE_CONTAINER* zone = board->GetArea( zonescount ); zone; zone = board->GetArea( zonescount ) ) { picker.SetItem( zone ); undoListPicker.PushItem( picker ); zonescount++; view->Add( zone ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, zone ); } if( undoListPicker.GetCount() == 0 ) return 0; editFrame->SaveCopyInUndoList( undoListPicker, UR_NEW ); // Synchronize layers // we should not ask PLUGINs to do these items: int copperLayerCount = board->GetCopperLayerCount(); if( copperLayerCount > initialCopperLayerCount ) board->SetCopperLayerCount( copperLayerCount ); // Enable all used layers, and make them visible: LSET enabledLayers = board->GetEnabledLayers(); enabledLayers |= initialEnabledLayers; board->SetEnabledLayers( enabledLayers ); board->SetVisibleLayers( enabledLayers ); editFrame->ReCreateLayerBox(); editFrame->ReFillLayerWidget(); static_cast<PCB_DRAW_PANEL_GAL*>( editFrame->GetGalCanvas() )->SyncLayersVisibility( board ); // Ratsnest board->BuildListOfNets(); board->SynchronizeNetsAndNetClasses(); board->GetRatsnest()->Recalculate(); // Start dragging the appended board VECTOR2D v( static_cast<BOARD_ITEM*>( undoListPicker.GetPickedItem( 0 ) )->GetPosition() ); getViewControls()->WarpCursor( v, true, true ); m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); return 0; }
bool PCB_EDIT_FRAME::AppendBoardFile( const wxString& aFullFileName, int aCtl ) { IO_MGR::PCB_FILE_T pluginType = plugin_type( aFullFileName, aCtl ); PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); // keep trace of existing items, in order to know what are the new items // (for undo command for instance) // Tracks are inserted, not append, so mark existing tracks to know what are // the new tracks for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) track->SetFlags( FLAG0 ); // Other items are append to the item list, so keep trace to the // last existing item is enough MODULE* module = GetBoard()->m_Modules.GetLast(); BOARD_ITEM* drawing = GetBoard()->m_Drawings.GetLast(); int zonescount = GetBoard()->GetAreaCount(); // Keep also the count of copper layers, because we can happen boards // with different copper layers counts, // and the enabled layers int initialCopperLayerCount = GetBoard()->GetCopperLayerCount(); LSET initialEnabledLayers = GetBoard()->GetEnabledLayers(); try { PROPERTIES props; char xbuf[30]; char ybuf[30]; // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet. sprintf( xbuf, "%d", GetPageSizeIU().x ); sprintf( ybuf, "%d", GetPageSizeIU().y ); props["page_width"] = xbuf; props["page_height"] = ybuf; GetDesignSettings().m_NetClasses.Clear(); pi->Load( aFullFileName, GetBoard(), &props ); } catch( const IO_ERROR& ioe ) { for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) track->ClearFlags( FLAG0 ); wxString msg = wxString::Format( _( "Error loading board.\n%s" ), GetChars( ioe.What() ) ); DisplayError( this, msg ); return false; } // Now prepare a block move command to place the new items, and // prepare the undo command. BLOCK_SELECTOR& blockmove = GetScreen()->m_BlockLocate; HandleBlockBegin( NULL, BLOCK_PRESELECT_MOVE, wxPoint( 0, 0) ); PICKED_ITEMS_LIST& blockitemsList = blockmove.GetItems(); PICKED_ITEMS_LIST undoListPicker; ITEM_PICKER picker( NULL, UR_NEW ); EDA_RECT bbox; // the new items bounding box, for block move bool bboxInit = true; // true until the bounding box is initialized for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) { if( track->GetFlags() & FLAG0 ) { track->ClearFlags( FLAG0 ); continue; } track->SetFlags( IS_MOVED ); picker.SetItem( track ); undoListPicker.PushItem( picker ); blockitemsList.PushItem( picker ); if( bboxInit ) bbox = track->GetBoundingBox(); else bbox.Merge( track->GetBoundingBox() ); bboxInit = false; } if( module ) module = module->Next(); else module = GetBoard()->m_Modules; for( ; module; module = module->Next() ) { module->SetFlags( IS_MOVED ); picker.SetItem( module ); undoListPicker.PushItem( picker ); blockitemsList.PushItem( picker ); if( bboxInit ) bbox = module->GetBoundingBox(); else bbox.Merge( module->GetBoundingBox() ); bboxInit = false; } if( drawing ) drawing = drawing->Next(); else drawing = GetBoard()->m_Drawings; for( ; drawing; drawing = drawing->Next() ) { drawing->SetFlags( IS_MOVED ); picker.SetItem( drawing ); undoListPicker.PushItem( picker ); blockitemsList.PushItem( picker ); if( bboxInit ) bbox = drawing->GetBoundingBox(); else bbox.Merge( drawing->GetBoundingBox() ); bboxInit = false; } for( ZONE_CONTAINER* zone = GetBoard()->GetArea( zonescount ); zone; zone = GetBoard()->GetArea( zonescount ) ) { zone->SetFlags( IS_MOVED ); picker.SetItem( zone ); undoListPicker.PushItem( picker ); blockitemsList.PushItem( picker ); zonescount++; if( bboxInit ) bbox = zone->GetBoundingBox(); else bbox.Merge( zone->GetBoundingBox() ); bboxInit = false; } SaveCopyInUndoList( undoListPicker, UR_NEW ); // we should not ask PLUGINs to do these items: int copperLayerCount = GetBoard()->GetCopperLayerCount(); if( copperLayerCount > initialCopperLayerCount ) GetBoard()->SetCopperLayerCount( copperLayerCount ); // Enable all used layers, and make them visible: LSET enabledLayers = GetBoard()->GetEnabledLayers(); enabledLayers |= initialEnabledLayers; GetBoard()->SetEnabledLayers( enabledLayers ); GetBoard()->SetVisibleLayers( enabledLayers ); ReCreateLayerBox(); ReFillLayerWidget(); if( IsGalCanvasActive() ) static_cast<PCB_DRAW_PANEL_GAL*>( GetGalCanvas() )->SyncLayersVisibility( GetBoard() ); GetBoard()->BuildListOfNets(); GetBoard()->SynchronizeNetsAndNetClasses(); SetStatusText( wxEmptyString ); BestZoom(); // Finish block move command: wxPoint cpos = GetNearestGridPosition( bbox.Centre() ); blockmove.SetOrigin( bbox.GetOrigin() ); blockmove.SetSize( bbox.GetSize() ); blockmove.SetLastCursorPosition( cpos ); HandleBlockEnd( NULL ); return true; }